c# - 当您还需要“默认”具体依赖项时,哪个是更好的依赖注入模式?
问题描述
我已经使用了以下两种模式来进行可测试性,我想知道哪个是更好的 OOP/SOLID。
模式一:提供两个构造函数,其中一个创建具体依赖
public MyClass
{
private IDependency dependency;
public MyClass() : this(new ConcreteDependency()) { }
public MyClass(IDependency dependency)
{
this.dependency = dependency;
}
}
模式 2:基类具有依赖初始化器,派生类使用具体依赖调用它
public abstract MyClassBase
{
private IDependency dependency;
protected void Initialize(IDependency dependency)
{
this.dependency = dependency;
}
}
public MyClass : MyClassBase
{
public MyClass()
{
Initialize(new ConcreteDependency());
}
}
解决方案
两个提供的示例都展示了Control Freak反模式,如Dependency Injection, Second Edition Principles, Practices, and Patterns中所述。
Control Freak反模式出现:
每次您在Composition Root以外的任何地方依赖 Volatile Dependency时。这违反了依赖倒置原则
在第一个示例中,即使MyClass
使用了IDependency
抽象,它也会拖着对具体ConcreteDependency
组件的引用,导致两个类紧密耦合。
在您的第二个示例中发生了同样的紧密耦合,这实际上是相同的反模式。此外,第二个示例甚至使用一种Initialize
方法将依赖项应用于已创建的MyClassBase
. 这会导致Temporal Coupling,这本身就是一种代码异味。
适当的解决方案可以防止导致紧密耦合和时间耦合,这意味着您使用构造函数注入并仅定义一个构造函数:
public MyClass
{
private IDependency dependency;
public MyClass(IDependency dependency)
{
this.dependency = dependency ?? throw new ArgumentNullException("dependency");
}
}
推荐阅读
- python - 我们可以将 .txt 文件导入 python 吗?
- session - Veracode CWE ID 259
- supercollider - Supercollider 3.9 中无法理解错误消息“addr”
- php - 如何将 PHP 回显到链接中
- oracle - pl/sql 中的变量。这段代码在做什么?
- hyperledger-fabric - 我应该如何在 Hyperledger Fabric 中设置渠道和组织?
- ios - 如何在 Swift 的泛型中声明基类?
- javascript - 如果将再次插入元素,则从对象数组中删除元素
- excel - 除非显示电子邮件,否则图像不会替换电子邮件正文中的文本,为什么?
- apache-spark - spark-submit 无限运行 - 显示错误:请求删除执行程序 n - 要求删除不存在的执行程序 n+1