Pat*_*ski 116 .net c# oop constructor dependency-injection
在一些情况下,我最常使用"混蛋注射".当我有一个"适当的"依赖注入构造函数时:
public class ThingMaker {
...
public ThingMaker(IThingSource source){
_source = source;
}
Run Code Online (Sandbox Code Playgroud)
但是,对于我打算作为公共API(其他开发团队将使用的类)的类,我永远找不到比编写具有最可能需要的依赖项的默认"bastard"构造函数更好的选择:
public ThingMaker() : this(new DefaultThingSource()) {}
...
}
Run Code Online (Sandbox Code Playgroud)
这里明显的缺点是,这会对DefaultThingSource产生静态依赖; 理想情况下,没有这种依赖性,消费者总是会注入他们想要的任何IThingSource.但是,这太难用了; 消费者希望新建一个ThingMaker并开始制作物品,然后几个月后,在需要时注入其他东西.在我看来,这只留下了几个选项:
男孩,#3肯定看起来很有吸引力.还有另一种更好的选择吗?#1或#2似乎不值得.
Mar*_*ann 60
据我所知,这个问题涉及如何使用一些适当的默认值公开松散耦合的API.在这种情况下,您可能具有良好的本地默认值,在这种情况下,依赖关系可以视为可选.处理可选依赖项的一种方法是使用Property Injection而不是Constructor Injection - 事实上,这是属性注入的海报场景.
但是,Bastard Injection的真正危险是当默认值为Foreign Default时,因为这意味着默认构造函数拖拽与实现默认值的程序集之间的不合需要的耦合.但是,据我理解这个问题,预期的默认值将来自同一个程序集,在这种情况下,我没有看到任何特别的危险.
在任何情况下,您也可以考虑我之前的一个答案中描述的Facade:依赖注入(DI)"友好"库
顺便说一句,这里使用的术语基于我书中的模式语言.
Ste*_*son 32
我的权衡取决于@BrokenGlass:
1)唯一构造函数是参数化构造函数
2)使用工厂方法创建ThingMaker并传入该默认源.
public class ThingMaker {
public ThingMaker(IThingSource source){
_source = source;
}
public static ThingMaker CreateDefault() {
return new ThingMaker(new DefaultThingSource());
}
}
Run Code Online (Sandbox Code Playgroud)
显然这并没有消除你的依赖性,但它确实让我更清楚的是,这个对象具有调用者可以深入研究的依赖关系.如果你喜欢(CreateThingMakerWithDefaultThingSource),你可以使工厂方法更加明确,如果这有助于理解.我更喜欢这个来覆盖IThingSource工厂方法,因为它继续支持组合.您还可以在DefaultThingSource废弃时添加新的工厂方法,并使用DefaultThingSource清楚地查找所有代码并将其标记为要升级.
您已经涵盖了问题的可能性.其他地方的工厂类为了方便或在课堂本身的一些便利.唯一另一个没有吸引力的选择是基于反射,甚至进一步隐藏依赖.
如果你必须有一个"默认"依赖项,也称为穷人的依赖注入,那么你必须在某处初始化并"连接"依赖项.
我将保留两个构造函数,但只有初始化工厂.
public class ThingMaker
{
private IThingSource _source;
public ThingMaker(IThingSource source)
{
_source = source;
}
public ThingMaker() : this(ThingFactory.Current.CreateThingSource())
{
}
}
Run Code Online (Sandbox Code Playgroud)
现在在工厂中创建默认实例并允许覆盖该方法:
public class ThingFactory
{
public virtual IThingSource CreateThingSource()
{
return new DefaultThingSource();
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
为什么使用两个构造函数: 两个构造函数清楚地显示了如何使用该类.无参数构造函数声明:只需创建一个实例,该类将执行其所有职责.现在第二个构造函数声明该类依赖于IThingSource,并提供了一种使用不同于默认实现的实现的方法.
为什么使用工厂: 1-纪律:创建新实例不应该是此类职责的一部分,工厂类更合适.2-干:想象一下,在同一个API中,其他类也依赖于IThingSource并做同样的事情.一旦返回IThingSource的工厂方法和API中的所有类自动开始使用新实例,就覆盖.
我没有看到将ThingMaker与IThingSource的默认实现耦合的问题,只要这个实现对整个API有意义,并且您提供了为测试和扩展目的覆盖此依赖关系的方法.