Ioc中繁忙的构造函数 - 它们是代码味道吗?

时间:2012-06-01 16:18:24

标签: c# .net design-patterns constructor inversion-of-control

我最终得到了一个看起来像这样的构造函数,同时试图找到一个我可以轻松测试的对象。

 public UserProvider(
            IFactory<IContainer> containerFactory,
            IRepositoryFactory<IUserRepository> userRepositoryFactory,
            IFactory<IRoleProvider> roleProviderFactory,
            IFactory<IAuthenticationProvider> authenticationProviderFactory,
            IFactory<IEmailAdapter> emailAdapterFactory,
            IFactory<IGuidAdapter> guidAdapterFactory,
            IRepositoryFactory<IVehicleRepository> vehicleRepositoryFactory,
            IRepositoryFactory<IUserVehicleRepository> userVehicleRepositoryFactory,
            IFactory<IDateTimeAdapter> dateTimeAdapterFactory)

这是对象将拥有的所有依赖项,并且是我拥有的最繁忙的构造函数。但如果有人看到这会真的会引起很大的影响吗?

我的目标是最终得到易于测试的逻辑。虽然它需要大量的模拟,但它确实很容易验证我的逻辑。但是我担心我可能会得到太多好事。

我很好奇大多数人实施ioc是否正常。

我可以进行一些简化 - 例如我不需要为几个适配器传递工厂,因为我可以直接传递适配器,因为它没有内部状态。但我真的在询问参数的数量。

或者更重要的是,我正在寻求保证我不会过火;)

但是我开始认为UserProvider类应该被分解一点 - 但最后我得到了更多的管道,这正是推动这个问题的原因。

我想如果我有这些顾虑,我应该考虑使用服务定位器模式吗?

2 个答案:

答案 0 :(得分:6)

当使用DI和构造函数注入违反SRP变得非常明显。这实际上是一件好事,而不是DI / IOC的错。如果你没有使用构造函数注入,那么该类将具有相同的依赖关系,它将不会显示为可见。

你在具体例子中可以做的是隐藏幕墙背后的一些相关依赖。例如,IVehicleRepository和IUserVehicleRepository可以隐藏在IVehicle外观后面。将IUs​​erRepository,IRoleProvider和IAuthenticationProvider置于幕后也是有意义的。

答案 1 :(得分:3)

在我看来,构造函数的参数很多。这就是我如何处理这个以获得良好的可测试性并减少“代码味道”。

  1. 不是传入工厂来创建类的实例,而只是传递类本身。这会自动将您的依赖项减少一半,因为UserProvider不会关心创建它需要的任何对象(并在必要时随后处理它们)它只会使用给它的内容而不是使用它创建对象所需的工厂它需要的实例。
  2. 从构造函数中删除适配器,只需在UserProvider中创建这些接口的实例。想想你多久需要改变格式化guid的方式。只要您的适配器没有很多依赖项,这仍然是可测试的。
  3. 我要说的是在可测试性和实用性之间取得良好的平衡。实现Ioc时,请尝试确定过去在可测试性方面遇到问题的地方以及维护和更改代码时出现问题的原因,因为依赖项太多了。这就是你会看到最大利益的地方。