用于从文件加载数据的C#类设计
如果我需要一个从文件加载数据的类(同时将加载函数保留在另一个类中),那么正确的(或好的)设计是什么 这就是我现在拥有的。尽管如此,我还是忍不住认为有更好的方法来构建它。让我大吃一惊的是,加载程序必须在继续之前调用Primary中的方法用于从文件加载数据的C#类设计,c#,class-design,C#,Class Design,如果我需要一个从文件加载数据的类(同时将加载函数保留在另一个类中),那么正确的(或好的)设计是什么 这就是我现在拥有的。尽管如此,我还是忍不住认为有更好的方法来构建它。让我大吃一惊的是,加载程序必须在继续之前调用Primary中的方法 class Primary { public int x1, x2, x3; //data that is read from file or calculated public void LoadPrimary { Loader L = n
class Primary {
public int x1, x2, x3; //data that is read from file or calculated
public void LoadPrimary {
Loader L = new Loader();
L.Load(this); //pass self as parameter (this can't be the best way though)
}
public void DoStuff() {
x1++; x2--;
}
}
class Loader {
public void Load(Primary PrimToLoad) {
PrimToLoad.x1 = 2; PrimToLoad.x2 = 4;
PrimToLoad.DoStuff(); //call a method in the calling class (better way for this?)
PrimToLoad.x3 = 6;
}
}
class Stub {
public void SomeMethod() {
Primary P = new Primary();
P.LoadPrimary();
}
}
在我的实际代码中,我使用Loader类来封装从各种源读取的几种不同格式(因此有多个加载函数),否则我只需将函数包含在Primary中,就可以使用它了。有没有办法让Loader类返回主类而不是void(现在它正在传递一个参数)。这样的设计似乎太“耦合”了
有没有更好的方法来完成这个场景的建议?我认为这很常见,但只是对类设计或术语了解不够,无法在google/SO/etc上找到答案(如何在字典中搜索无法拼写的单词)
更新/注释这两个答案(到目前为止)都指向工厂模式。这是否意味着对于每个加载方法,我必须有一个单独的类?在我的特殊情况下似乎有点过分了。这是否也意味着我的存根类必须知道/决定文件的格式(以便它可以调用正确的工厂类),而不是让主类担心它?似乎在用耦合换取封装 我当然知道我应该使用属性(实际上是am)和接口(实际上是am),但我想简化它以解决这个问题。没有考虑注射方面,这是一个很好的建议
如果有人能更新他们的答案来显示多个加载函数是如何工作的(请保持简单),我很可能会接受。我还考虑将加载函数移回Primary类中作为替代解决方案。实际上有几十种模式设计用于完成此任务,您选择的模式取决于系统的复杂性、灵活性和可伸缩性 您的解决方案并不糟糕,但我建议您创建一个接口ILoader,并使用Loader实现它。此外,您不应该在Primary中“新建”加载程序,而应该在构造函数中或在Primary上使用属性将ILoader添加到Primary中。如果您愿意,您仍然可以保留一个默认实现,该实现可以在一个具体的加载程序中更新。下面是一个例子:
class Primary {
public int x1, x2, x3; //data that is read from file or calculated
private ILoader _loader;
public Primary(ILoader loader) {
_loader = loader;
}
public Primary() {
_loader = new Loader();
}
public void LoadPrimary {
_loader.Load(this);
}
public void DoStuff() {
x1++; x2--;
}
}
interface ILoader {
void Load(Primary primToLoad);
}
class Loader : ILoader {
public void Load(Primary PrimToLoad) {
L.x1 = 2; L.x2 = 4;
L.DoStuff(); //call a method in the calling class (better way for this?)
L.x3 = 6;
}
}
class Stub {
public void SomeMethod() {
Primary P = new Primary(new Loader());
P.LoadPrimary();
}
}
此方法使依赖项对客户端显式显示。它还允许您使用ILoader的模拟实现进行测试。此外,您可以轻松地将ILoader的实现更改为使用数据库、web服务等
另一个注意事项是,我并不特别喜欢将您的对象传递给Loader并让Loader修改它。我更愿意实例化一个加载程序,并要求它从头构造一个对象。当我要求其他物体改变我自己东西的状态时,我总是有一种不舒服的感觉。这个实现看起来像工厂模式
还有一个小问题,我看到您正在使用公共字段作为数据。这是一个大禁忌,你应该用它来代替。属性支持封装和二进制兼容性
您可能希望了解的另一个数据访问策略是:糟糕的设计,但易于理解的实现,适用于小型系统。为完成此任务设计了几十种模式,您选择的模式取决于系统的复杂性、灵活性和可伸缩性 您的解决方案并不糟糕,但我建议您创建一个接口ILoader,并使用Loader实现它。此外,您不应该在Primary中“新建”加载程序,而应该在构造函数中或在Primary上使用属性将ILoader添加到Primary中。如果您愿意,您仍然可以保留一个默认实现,该实现可以在一个具体的加载程序中更新。下面是一个例子:
class Primary {
public int x1, x2, x3; //data that is read from file or calculated
private ILoader _loader;
public Primary(ILoader loader) {
_loader = loader;
}
public Primary() {
_loader = new Loader();
}
public void LoadPrimary {
_loader.Load(this);
}
public void DoStuff() {
x1++; x2--;
}
}
interface ILoader {
void Load(Primary primToLoad);
}
class Loader : ILoader {
public void Load(Primary PrimToLoad) {
L.x1 = 2; L.x2 = 4;
L.DoStuff(); //call a method in the calling class (better way for this?)
L.x3 = 6;
}
}
class Stub {
public void SomeMethod() {
Primary P = new Primary(new Loader());
P.LoadPrimary();
}
}
此方法使依赖项对客户端显式显示。它还允许您使用ILoader的模拟实现进行测试。此外,您可以轻松地将ILoader的实现更改为使用数据库、web服务等
另一个注意事项是,我并不特别喜欢将您的对象传递给Loader并让Loader修改它。我更愿意实例化一个加载程序,并要求它从头构造一个对象。当我要求其他物体改变我自己东西的状态时,我总是有一种不舒服的感觉。这个实现看起来像工厂模式
还有一个小问题,我看到您正在使用公共字段作为数据。这是一个大禁忌,你应该用它来代替。属性支持封装和二进制兼容性
您可能希望了解的另一个数据访问策略是:糟糕的设计,但易于理解的实现,适用于小型系统。这看起来像是工厂模式的一个非常简单的示例。但是,您不希望创建的对象了解工厂。因此,请删除LoadPrimary(),并改为执行以下操作:
class Primary {
public int x1, x2, x3; //data that is read from file or calculated
public void DoStuff() {
x1++; x2--;
}
}
public interface PrimaryFactory
{
Primary Load();
}
public class FileTypeAPrimaryFactory {
FileTypeAPrimaryFactory(File f)
{
...
}
public void Load() {
var item = new Primary();
item.x1 = 2; PrimToLoad.x2 = 4;
item.DoStuff();
item.x3 = 6;
}
}
public class FileTypeBPrimaryFactory {
FileTypeBPrimaryFactory(File f)
{
...
}
public void Load() {
var item = new Primary();
item.x1 = 2; PrimToLoad.x2 = 4;
item.DoStuff();
item.x3 = 6;
}
}
class Stub {
public void SomeMethod() {
PrimaryFactory factory = PrimaryFactory(<get file>);
Primary P = factory.Load();
}
public PrimaryFactory(File file)
{
if (<check file format>) return new FileTypeAPrimaryFactory(file);
return new FileTypeBPrimaryFactory(file);
}
}
类主{
public int x1,x2,x3;//从文件读取或计算的数据
公共空间{
x1++;x2--;
}
}
公共接口主工厂
{
主荷载();
}
公共类FileTypeAPrimaryFactory{
文件类型APRIMARYFactory(文件f)
{
...
}
公共空荷载(){
var item=newprimary();
item.x1=2;PrimToLoad.x2=4;
项目.DoStuff();
项目3.x3=6;
}
}
公共类FileTypeBPrimaryFactory{
FileTypeBPrimaryFactory(文件f)
{
...
}
公共空荷载(){
var item=newprimary();
item.x1=2;PrimToLoad.x2=4;
项目.DoStuff();
项目3.x3=6;
}
}
类存根{
公共方法(){
PrimaryFactory=PrimaryFactory();
初级P