首页 > 解决方案 > 当您还需要“默认”具体依赖项时,哪个是更好的依赖注入模式?

问题描述

我已经使用了以下两种模式来进行可测试性,我想知道哪个是更好的 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());
    }
}

标签: c#oopdesign-patternsdependency-injection

解决方案


两个提供的示例都展示了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");
    }
}

推荐阅读