混合基于构造函数和基于setter的注入是一件坏事吗?

Nik*_*hev 13 oop setter refactoring dependency-injection

我有一个从CSV文件操作导入产品的类,需要大约7个参数.这是进口商绝对需要的信息.

所有这些参数都具有相同的使用寿命.最后,我们必须有一个不可变对象.

我太害怕在构造函数中列出所有这些因为它对可读性的影响并且决定将其中的3个移动到setter注入.但显然这不是一个优雅的解决方案.

问题:

1)混合基于构造函数和基于setter的注射是不好的做法吗?

2)如何解决这个特殊问题?

我正在考虑应用Martin Fowler的"引入参数对象"重构,但这有一个问题.

4参数可以很容易地移动到Parameter对象(customerId,projectId,languageId等) - 所有整数.

其他3个参数是我注入的对象(模拟单元测试需要它).

Mar*_*ann 26

混合构造函数注入和属性注入并不一定是坏事,但它可能不常见.作为一个整体策略,避免使用属性注入,因为它更难以正确实现(这听起来可能违反直觉,但这是真的).

了解何时使用每种模式非常重要.

  • 构造函数注入应该是您的默认注入模式.它非常容易实现并且可以保证不变量:将其分配给只读字段以确保消费者的不变量.
  • 当您具有良好的本地默认实现时,可以使用属性注入,但是您希望遵循开放/封闭原则并允许高级用户通过提供替代实现来扩展该类.

你不应该因为构造化妆品而使用Property Injection.

当您需要太多依赖项时,这表明您可能违反了单一责任原则 - 该类只是试图立即执行太多操作.

不是引入参数对象(否则是一个好的建议),更好的选择是将两个或多个依赖项封装到聚合服务中,该聚合服务协调这些依赖项的交互.

想象一下,您的初始构造函数如下所示:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)
Run Code Online (Sandbox Code Playgroud)

在应用了一些分析后,您会发现在这种情况下, IDep1,IDep3和IDep4将以特定方式一起使用.这将允许您引入封装这些的聚合服务,如下所示:

public class AggService : IAggService
{
    public AggService(IDep1 dep1, IDep3 dep3, IDep4 dep4)
    {
        // ...
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

您现在可以将原始构造函数重写为:

public MyClass(IAggService aggSrvc, IDep2 dep2, IDep5 dep5)
Run Code Online (Sandbox Code Playgroud)

等等......

通常,聚合服务本身就是一个合适的概念,突然间你拥有的API比你开始时更丰富.