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

发布于 2024-08-16 10:15:29 字数 477 浏览 1 评论 0原文

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

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

我不敢在构造函数中列出所有这些,因为它会影响可读性,并决定将其中 3 个移至 setter 注入。但显然这不是一个优雅的解决方案。

问题:

1)混合基于构造函数和基于设置器的注入是一种不好的做法吗?

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

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

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

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

I have a class for products import from CSV file operation which requires about 7 parameters. This is an info which is definitely needed for importer.

All of this parameters have the same life time. In the end we must have an Immutable Object.

I was too scared to list all of them in constructor because of its affect to readability and decided to move 3 of them to setters injection. But obviously it's not an elegant solution.

Questions:

1) Is mixing constructor-based and setter-based injections a bad practice?

2) How this particular problem can be solved?

I was thinking about applying "Introduce Parameter Object" refactoring by Martin Fowler, but there is a problem with this.

4 Parameters can be moved to Parameter object quite easily (customerId, projectId, languageId etc.) - all integers.

Other 3 parameters are an object I inject(it is required for Mock unit-tests).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜雨飘雪 2024-08-23 10:15:29

混合使用构造函数注入和属性注入不一定是坏事,但可能并不常见。作为总体策略,请避免属性注入,因为正确实现它要困难得多(这可能听起来违反直觉,但确实如此)。

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

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

由于构造函数的修饰,您永远不应该应用属性注入。

当您需要太多依赖项时,就表明您可能违反了单一职责原则 -班级只是想同时做太多事情。

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

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

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)

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

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

    // ...
}

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

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

等等...

聚合服务本身就是一个正确的概念,这是很常见的,突然间您就拥有了比刚开始时更丰富的 API。

It's not necessarily a bad thing to mix Constructor Injection and Property Injection, but it may not be that common. As an overall strategy, avoid Property Injection since it's much more difficult to implement correctly (this may sound counter-intuitive, but it's true).

It's important to understand when to use each pattern.

  • Constructor Injection should be your default injection pattern. It's super-easy to implement and can guarantee invariants: assign it to a read-only field to ensure the consumer's invariants.
  • Property Injection can be used when you have a good Local Default implementation, but you want to follow the Open/Closed Principle and allow advanced users to extend the class by providing an alternative implementation.

You should never apply Property Injection because of constructor cosmetics.

When you require too many dependencies, it's a sign that you may be violating the Single Responsibility Principle - the class is simply trying to do too much at once.

Instead of introducing a Parameter Object (otherwise a good suggestion), a better option is to encapsulate two or more of the dependencies into an aggregating service that orchestrates the interaction of these dependencies.

Imagine that your initial constructor looks like this:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)

After applying a bit of analysis, you figure out that in this case IDep1, IDep3 and IDep4 will be used together in a particular way. This will allow you to introduce an aggregation service that encapsulated these like this:

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

    // ...
}

You can now rewrite the original constructor to this:

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

and so forth...

It is very common that the aggregate service turns out to be a proper concept in it's own right, and suddenly you have a richer API than when you started.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文