2011-02-14 42 views
0

如果我需要一个从文件加载其数据的类(同时将加载函数保留在不同的类中),什么是正确的(或良好的)设计?用于从文件加载数据的C#类设计

这就是我现在拥有的。不禁觉得有一个更好的方式来构建它的一切,但。绊倒我的部分是Loader必须在继续之前调用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类来封装从各种来源读了几种不同格式(所以有多个负载功能),否则,我只想包括主要功能,用它做。有没有办法让Loader类返回主而不是void(现在它传递一个Param)。这似乎太“耦合”成为这样的好设计。

有更好的方法来完成这种情况的任何建议?我认为这很常见,但只是不太了解课堂设计或术语,以便在google/SO/etc上找到答案(您如何在词典中搜索不能拼写的单词)。

更新/ Notes的
两个问题的答案(到目前为止)向工厂模式点。这是否意味着对于每个Load方法,我必须有一个单独的类?似乎在我的特殊情况下过度杀伤。这不也意味着我的Stub类必须知道/决定文件的格式(因此它可以调用正确的工厂类),而不是让Primary类担心它吗?似乎是封装交易耦合。

肯定知道我应该使用属性(实际上)和一个接口(实际上),但想要简化它的问题。没有考虑注射方面这是一个很好的建议。

如果任何人都可以更新他们的答案,以显示多个加载函数如何工作(请保持简单),我很可能会接受。我还在考虑将加载函数移回到Primary类中作为替代解决方案。

+0

我想是不是在课堂上执行任何逻辑的好方法,它负责装载数据(数据访问层,就像你的`Loader`类) 。 – whyleee 2011-02-14 21:26:58

+0

@whylee - 绝对同意你的观点。这就是为什么我试图把DoStuff函数放在Primary类中而不是在Loader类中。只是不知道这是否是正确的方式。 – ktharsis 2011-02-14 22:41:13

+0

如果可能,在`LoadPrimary()`方法中,您可以先调用`Loader.Load()`方法,然后调用`DoStuff()`方法。 – whyleee 2011-02-14 22:59:22

回答

1

这看起来像一个非常简单的工厂模式的例子。你不想让创建的对象知道工厂。因此,撕裂了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); 
    } 
} 
2

有几十种模式可以完成这项任务,您选择的模式取决于系统的复杂性,灵活性和可扩展性。

你的解决方案并不可怕,但我会建议创建一个接口,ILoader,并用Loader实现它。此外,不是在主服务器中“新建”一个Loader,而是在构造函数中或在主服务器上使用一个属性,将012oILoader放入Primary。如果你愿意的话,你仍然可以保持一个默认的实现,即一个具体的Loader的新闻。这里有一个例子:

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的实现来使用数据库,网络服务等。

另外需要注意的是我并不是特别喜欢将你的对象传入Loader并让Loader修改它。我宁愿实例化一个Loader,并要求它从头构建一个对象。当要求其他物体改变我自己的东西状态时,我总会感到不舒服。这个实现看起来像一个工厂模式。

还有一个小问题,我看到你正在为你的数据使用公共字段。这是一个很大的禁忌,你应该使用C# properties。属性支持封装和二进制兼容性。

您可能要考虑的另一种数据访问策略是Active Record-设计不好,但容易理解实现并适用于小型系统。