Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 混合使用基于构造函数和基于setter的注入是一件坏事吗?_Oop_Refactoring_Dependency Injection_Setter - Fatal编程技术网

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

Oop 混合使用基于构造函数和基于setter的注入是一件坏事吗?,oop,refactoring,dependency-injection,setter,Oop,Refactoring,Dependency Injection,Setter,我有一个从CSV文件导入产品的类,它需要大约7个参数。这是进口商绝对需要的信息 所有这些参数都具有相同的生存时间。最后,我们必须有一个明确的目标 我太害怕了,不敢在构造函数中列出它们,因为这会影响可读性,所以决定将其中的3个移到setters注入中。但显然这不是一个优雅的解决方案 问题: 1) 混合基于构造函数和基于setter的注入是一种糟糕的做法吗 2) 如何解决这个特殊问题 我曾考虑应用Martin Fowler的“引入参数对象”重构,但这有一个问题 4个参数可以很容易地移动到参数对象(c

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

所有这些参数都具有相同的生存时间。最后,我们必须有一个明确的目标

我太害怕了,不敢在构造函数中列出它们,因为这会影响可读性,所以决定将其中的3个移到setters注入中。但显然这不是一个优雅的解决方案

问题:

1) 混合基于构造函数和基于setter的注入是一种糟糕的做法吗

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

我曾考虑应用Martin Fowler的“引入参数对象”重构,但这有一个问题

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


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

混合构造函数注入和属性注入并不一定是坏事,但可能并不常见。作为一个整体策略,避免属性注入,因为它更难正确实现(这听起来可能有悖常理,但事实确实如此)

了解何时使用每个模式很重要

  • 构造函数注入应该是您的默认注入模式。它非常容易实现,并且可以保证不变量:将其分配到只读字段以确保消费者的不变量
  • 当您有一个良好的本地默认实现时,可以使用属性注入,但您希望遵循,并允许高级用户通过提供替代实现来扩展类
您永远不应该应用属性注入,因为这是一个错误

当您需要太多依赖项时,这表明您可能违反了规则-该类只是试图一次做太多

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

假设您的初始构造函数如下所示:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)
public class AggService : IAggService
{
    public AggService(IDep1 dep1, IDep3 dep3, IDep4 dep4)
    {
        // ...
    }

    // ...
}
在应用一些分析之后,您会发现在本例中,IDep1、IDep3和IDep4将以特定的方式一起使用。这将允许您引入一个聚合服务,该服务封装如下:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)
public class AggService : IAggService
{
    public AggService(IDep1 dep1, IDep3 dep3, IDep4 dep4)
    {
        // ...
    }

    // ...
}
现在可以将原始构造函数重写为:

public MyClass(IAggService aggSrvc, IDep2 dep2, IDep5 dep5)
等等


聚合服务本身就是一个合适的概念,这是很常见的,突然之间,您的API比开始时更丰富。

这将取决于您的DI容器。。。有些人比其他人更容易做到这一点。@skaffmann:我强烈反对。DI模式的使用不应该由DI容器的选择决定——容器是用来帮助你的,而不是约束你的。@Nikita——为什么不引入完整的参数对象并将模拟注入参数?聚合服务与参数对象有何不同?听起来你是在暗示它可能与域模型有一种更具表现力、更具体的关系,但对于设计良好的参数对象来说应该是这样,不是吗?@Jeff Sternal:聚合服务可能与参数对象没有太大区别,但聚合服务更倾向于好莱坞原则(一件好事)。参数对象通常只是包含相关对象的结构,您可以单独提取和使用这些对象。聚合服务将对使用者隐藏这些依赖项,而不是提供整体功能。这并不是一个明确的区别,但是…@Mark:我可以找到有关参数之间区别的更多信息吗对象和聚合服务在您的书《.NET中的依赖注入》中?