用目录概念代替复杂的构造函数?

时间:2018-08-09 21:07:54

标签: c# dependency-injection simple-injector

在我当前的项目中,我的经理正在强迫我介绍一些有关依赖注入的设计概念,因为我很好奇依赖注入专家对这种方法的看法。其背后的思想是使用称为目录的类,该类针对每个服务(Service Fabric中的服务)实现,并且内部具有所有依赖项,如下所示:

public interface IDepA
{
}

public interface IDepB
{
}

public interface IDepC
{
}

public class StandardConstructorInjectorService
{
    private readonly IDepA _depA;
    private readonly IDepB _depB;
    private readonly IDepC _depC;

    public StandardConstructorInjectorService(IDepA depA, IDepB depB, IDepC depC)
    {
        _depA = depA;
        _depB = depB;
        _depC = depC;
    }
}

public class ServiceCatalog
{
    private readonly Container _container;

    public ServiceCatalog(Container container)
    {
        _container = container;
    }

    public IDepA DepA => _container.GetInstance<IDepA>();
    public IDepB DepB => _container.GetInstance<IDepB>();
    public IDepC DepC => _container.GetInstance<IDepC>();
}

public class ServiceWithCatalog
{
    private readonly ServiceCatalog _catalog;

    public ServiceWithCatalog(ServiceCatalog catalog)
    {
        _catalog = catalog;
    }
}

从我的角度来看,我们有

优点:

  1. 使用目录的代码很简单
  2. 依赖项可以在懒惰模式下使用,因此当代码逻辑不使用它们时,它们将不会被创建-但另一方面,我知道我们应该以这样的方式设计类,以使其使用所有依赖项
  3. 引导这些类很容易,因为它们具有一个预定义的目录

缺点:

  1. 对类的依赖关系不是直接可见的
  2. 闻到服务定位符,但我们仅在目录定义中使用resolve,而不在业务代码中使用resolve,因此我不确定这是否可以接受,或者依赖注入警察会追捕我们:)

您如何看待这种方法?

1 个答案:

答案 0 :(得分:3)

您的ServiceCatalog类取决于Container。这实际上使它成为服务定位符,即anti-pattern。此类不是“业务代码”的事实是无关紧要的。唯一重要的是它不是Composition Root 部分,这使它成为反模式。

除了使用反模式外,类还公开了其依赖项,而不是隐藏,这也是一个坏主意。该类的主要思想可能是将常用的依赖项分组在一起,从而减少一个类具有的构造函数依赖项的数量。但是,与此有关的问题是,它不会降低消费类的复杂性,而只是掩盖了类具有过多依赖性的事实。具有过多依赖性的类可能违反单一责任原则

不要使用此服务目录“模式”,而要使用构造函数注入。当类获得过多的构造函数依赖关系时,应采取称为 Constructor Over-Injection 的代码气味。有许多解决方案,例如Facade Services,装饰器或域事件。外观服务隐藏而不是暴露其依赖。

Mark Seemann和我自己可以在this book中阅读所有这些信息以及更多内容。