如果我需要一个从文件加载数据的类(同时将加载函数保存在不同的类中),那么正确(或好)的设计是什么?
这就是我现在所拥有的。不禁认为有一种更好的方法来构建它。绊倒我的部分是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类来封装从各种源读取的几种不同格式(因此有多个Load函数),否则我只需要在Primary中包含该函数并完成它。有没有办法让Loader类返回Primary而不是void(现在它正在传递一个Param)。它似乎太“耦合”,以这种方式做好设计。
有关更好地完成此方案的任何建议吗?我认为它很常见但是对于类设计或术语不够了解,无法在google / SO /等上找到答案(如何在字典中搜索无法拼写的单词)。
更新/注释
答案(到目前为止)都指向工厂模式。这是否意味着对于每个Load方法,我必须有一个单独的类?在我的特定情况下似乎有点矫枉过正。这是否也意味着我的Stub类必须知道/决定文件的格式(因此它可以调用正确的工厂类)而不是让Primary类担心它?似乎是用于封装的交易耦合。
绝对知道我应该使用属性(实际上是)和接口(实际上是)但是想要简化问题。没想到注射方面这是一个很好的建议。
如果有人可以更新他们的答案以显示多个加载功能如何工作(请保持简单)我很可能会接受。我也在考虑将负载功能移回到Primary类中作为替代解决方案。
答案 0 :(得分:2)
实际上有几十种模式可以完成这项任务,您选择的模式取决于系统的复杂性,灵活性和可扩展性。
您的解决方案并不可怕,但我建议您创建一个界面,ILoader,并使用Loader实现它。此外,您不应在主要内部“新建”Loader,而应将inject ILoader转换为Primary,无论是在构造函数中还是在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的实现更改为使用数据库,Web服务等。
另一个注意事项是,我并不是特别喜欢将你的对象传递给Loader并让Loader修改它。我宁愿实例化一个Loader并要求它从头开始构造一个对象。当要求其他物体改变我自己的东西状态时,我总会感到有些不舒服。此实现看起来像工厂模式。
还有一点,我看到你正在使用公共字段来存储数据。这是一个很大的禁忌,你应该使用C# properties代替。属性支持封装和二进制兼容性。
您可能希望查看的另一种数据访问策略是Active Record - 设计错误,但易于理解工具并且适用于小型系统。
答案 1 :(得分:1)
这看起来像Factory模式的一个非常简单的例子。但是,您不希望创建的对象知道工厂。撕掉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);
}
}