假设我正在为我的应用程序定义一个浏览器实现类:
class InternetExplorerBrowser : IBrowser {
private readonly string executablePath = @"C:\Program Files\...\...\ie.exe";
...code that uses executablePath
}
乍一看,这可能看起来是个好主意,因为executablePath
数据靠近将要使用它的代码。
当我尝试在具有外语操作系统的另一台计算机上运行相同的应用程序时,问题就来了:executablePath
将具有不同的值。
我可以通过 AppSettings 单例类(或其等价物之一)来解决这个问题,但是没有人知道我的类实际上依赖于这个 AppSettings 类(这与 DI 理念背道而驰)。它也可能给单元测试带来困难。
executablePath
我可以通过构造函数传入来解决这两个问题:
class InternetExplorerBrowser : IBrowser {
private readonly string executablePath;
public InternetExplorerBrowser(string executablePath) {
this.executablePath = executablePath;
}
}
但这会在我Composition Root
的(将完成所有需要的类连接的启动方法)中引发问题,因为该方法必须知道如何连接事物并且必须知道所有这些小设置数据:
class CompositionRoot {
public void Run() {
ClassA classA = new ClassA();
string ieSetting1 = "C:\asdapo\poka\poskdaposka.exe";
string ieSetting2 = "IE_SETTING_ABC";
string ieSetting3 = "lol.bmp";
ClassB classB = new ClassB(ieSetting1);
ClassC classC = new ClassC(B, ieSetting2, ieSetting3);
...
}
}
这很容易变成一团糟。
我可以通过传递表单的接口来解决这个问题
interface IAppSettings {
object GetData(string name);
}
到所有需要某种设置的类。然后我可以将它实现为一个嵌入了所有设置的常规类,或者一个从 XML 文件中读取数据的类,类似的东西。如果这样做,我应该为整个系统提供一个通用的 AppSettings 类实例,还是让每个可能需要的类关联一个 AppSettings 类?这当然看起来有点矫枉过正。此外,将所有应用程序设置放在同一个位置可以轻松查看并查看在尝试将程序移动到不同平台时可能需要做的所有更改。
处理这种常见情况的最佳方法可能是什么?
编辑:
那么如何使用IAppSettings
所有硬编码的设置呢?
interface IAppSettings {
string IE_ExecutablePath { get; }
int IE_Version { get; }
...
}
这将允许编译时类型安全。如果我看到接口/具体类增长太多,我可以创建其他更小的表单接口IMyClassXAppSettings
。在医疗/大型项目中是否负担过重?
我还阅读了有关 AOP 及其处理横切关注点的优势(我想这是其中之一)。它不能也为这个问题提供解决方案吗?也许像这样标记变量:
class InternetExplorerBrowser : IBrowser {
[AppSetting] string executablePath;
[AppSetting] int ieVersion;
...code that uses executablePath
}
然后,在编译项目时,我们还将获得编译时安全性(让编译器检查我们是否实际实现了将编织数据的代码。当然,这会将我们的 API 绑定到这个特定的方面。