Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于从文件加载数据的C#类设计_C#_Class Design - Fatal编程技术网

用于从文件加载数据的C#类设计

用于从文件加载数据的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

如果我需要一个从文件加载数据的类(同时将加载函数保留在另一个类中),那么正确的(或好的)设计是什么

这就是我现在拥有的。尽管如此,我还是忍不住认为有更好的方法来构建它。让我大吃一惊的是,加载程序必须在继续之前调用Primary中的方法

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