没有构造函数的依赖注入:真的是一个不好的做法?

Seb*_*ero 3 c# structuremap asp.net-mvc dependency-injection recommendation-engine

我正在使用C#,MVC4,StructureMap等进行Web解决方案.

在解决方案中,我有控制器服务.举例:

public class ServiceA{
    private readonly IRepository _repository1;
    private readonly IRepository _repository2;

    public ServiceA(IRepository1 repository1, IRepository2 repository2){
        _repository1=repository1;
        _repository2=repository2;
    }

    public void DoSomethingA(){
        _repository1.DoSomething();
    }

    public void DoSomethingB(){
        _repository2.DoSomething();
    }
}

public class ServiceB{
    private readonly IRepository _repository3;
    private readonly IRepository _repository4;

    public ServiceB(IRepository3 repository3, IRepository4 repository4){
        _repository3=repository3;
        _repository4=repository4;
    }

    public void DoSomethingA(){
        _repository3.DoSomething();
    }

    public void DoSomethingB(){
        _repository4.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做是好的做法吗?:

public abstract class ServiceBase(){
    public IRepository1 Repository1 { get { return instanceOf<IRepository1>(); }}
    public IRepository2 Repository2 { get { return instanceOf<IRepository2>(); }}
    public IRepository3 Repository3 { get { return instanceOf<IRepository3>(); }}
    public IRepository4 Repository4 { get { return instanceOf<IRepository4>(); }}

    private T instanceOf<T>()
    {
        return ServiceLocator.Current.GetInstance<T>();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后以这种方式创建服务?

public class ServiceA : ServiceBase
{
    public void DoSomethingA(){
        Repository1.DoSomething();
    }

    public void DoSomethingB(){
        Repository2.DoSomething();
    }
}


public class ServiceB : ServiceBase
{
    public void DoSomethingA(){
        Repository3.DoSomething();
    }
    public void DoSomethingB(){
        Repository4.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

有了第二种选择,我看到了一些优势:

  • 没有必要为每个存储库提供私有变量.
  • 我不需要服务的构造函数,使它们更小,更容易阅读.
  • 所有存储库都可以在任何服务中使用.
  • 该服务不会获得不必要的实例.通过实例,调用ServiceA该方法DoSomethingAServiceLocator得到唯一Repository1实例.(使用第一种方法将接收两个实例:for Repository1Repository2)

在这两种情况下,我都可以进行适当的测试:

  • 在第一种情况下,通过构造函数发送模拟对象.
  • 在第二种情况下,配置StructureMap以在必要时使用模拟对象.

你认为?我反对某些原则?(对不起,我的英文)

Rem*_*oor 7

让我们先看看优势参数:

没有必要为每个存储库提供私有变量.

那是对的.虽然实际上这4个字节的参考通常无关紧要.

我不需要服务的构造函数,使它们更小,更容易阅读.

我看到的恰恰相反.有一个构造函数会立即告诉您该类具有哪些依赖项.使用基类,您必须查看整个类以获取该信息.此外,它使得无法使用工具来分析您是否具有低耦合,高内聚和无缠结的良好设计.那些使用该类的人根本不知道该类具有哪些依赖关系,除非他们阅读实现.

所有存储库都可以在任何服务中使用.

应避免在一个服务中使用多个repos,因为这会增加耦合.提供所有服务的所有回购是鼓励具有高耦合的糟糕设计的最佳方式.所以我认为这是一个缺点.

该服务不会获得不必要的实例.例如,在ServiceA中调用DoSomethingA方法,ServiceLocator只获取Repository1实例.(使用第一种方法将接收两个实例:对于Repository1和Repository2)

使用完全不同依赖关系的不同方法的服务是一个巨大的迹象,表明它不遵循单一责任原则.在这种情况下,最有可能将它分成两个服务.

关于可测试性:在第二种情况下,通过使用单例(ServiceLocator),您的测试不再被隔离.所以他们可以相互影响.特别是在并行运行时.

在我看来,你走错了路.使用Service Locator反模式,您将依赖性隐藏到使用您的类的人,这使得阅读实现的人更难以查看该类具有哪些依赖项,并且您的测试不再被隔离.