Setter Injection或Ambient Context模式

Tom*_*Tom 8 .net c# design-patterns dependency-injection

我有一些全局组件我不知道如何将它们放入设计中.如:

  • 设置类:它正在连接程序的初始设置,它可以是幕后的app.config(1way),web.config(1way),硬编码值(1way)或sqldb(2way).

  • 语言类:它包含不同的语言集,同样,我可以在它后面有一些resx文件(1way),硬编码值(1way)或sqldb(2way).

第一个问题是,我应该在依赖注入中创建这些类的setter属性(我使用Windsor):

public ISettings Settings {set;}
public ILanguage Language {set;}
Run Code Online (Sandbox Code Playgroud)

或者我应该将它们作为环境上下文:

string DoSomethingAndReportIt() {
    //do something ...
    var param = Settings.Current.SomeParam;
    //report it ...
    return Language.Current.SomeClass_SomeMethod_Job_Done;
}
Run Code Online (Sandbox Code Playgroud)

我注意到.net库中有一些实际使用环境上下文模式的组件,例如System.Security.Principal,System.Web.ProfileBase,System.Thread.CurrentCulture ...

您认为将我的全局类(如设置和语言)设置为环境上下文类是没有害处的吗?如果没有,为什么DI是首选?与环境相比,它们在单元测试中是否更有优势?

第二个问题是,如果DI更好,(我觉得DI模式是首选),有什么方法可以代理现有的环境类,如Security.Principal或Profile,以遵循DI模式?

Hus*_*vic 3

当您需要实现跨多个层的功能时,环境上下文就可以了。(在您的情况下,您说这两个对象是全局的)此功能称为横切关注点。正如您所注意到的,.NET 中的许多类都是作为环境上下文实现的,例如IPrincipal. 为了获得环境上下文实现的工作版本,您需要向您的SettingsLanguage对象提供一些默认值(如果它们是作为环境上下文开发的)。我的假设是您将提供ILanguage和的一些默认实现ISettings,并且考虑到您将在全球范围内使用它们,它们是环境上下文的良好候选者。

另一方面,您计划多久使用一次实现这两个接口的对象?Settings != null而且,意义和这两个物体的存在是否至关重要Language != null?如果您确实打算在一两个类中使用它们,和/或如果对象的存在并不重要,您可能需要使用setter 注入。setter 注入实际上并不需要默认值,因此您的对象可以是null.

就我个人而言,我不喜欢环境背景。但是,如果它被证明是最可接受的解决方案,我会使用它。对于您的实现,我会这样做:因为您需要初始化一次且仅在一个位置实现两个接口的对象,所以您可以从环境上下文开始。如果您意识到您在极少数位置使用它,请考虑将其重构为 setter 注入。如果对象的存在很重要,请考虑构造函数注入实现。