2

我知道这个论点在 SO 上得到了很好的介绍,尤其是在

为什么不使用 IoC 容器来解决实体/业务对象的依赖关系?

还有其他问题;但疑虑依然存在。

我使用了收集数据而不是实体业务对象的措辞类型,以使问题集中在原则上。

所以,如果我有一个依赖于这样的原始数据(甚至更多字段)的类型:

public class Animal {
  private readonly string name;
  private readonly string nickname;
  private readonly int weight;
  private readonly int heightAtWithers:
  private readonly Color mainColor;
  private raadonly bool isMale;
  private readonly bool isAggressive;

  public Animal(string name, string nickname, int weight,
                int heightAtWithers, Color mainColor,
                bool is Male, bool isAggressive)
  {
    // remainder omitted
  }

  public string Name { get { return this.name; } }

  // remainder omitted
}

这是构造函数过度注入的情况吗?

Mark Seemann书中,建议将依赖项的数量保持在 2 到 4 之间(如果我没记错的话)。

对于这种反模式不适用的类型是否可能?

4

2 回答 2

8

这些并不是通常意义上的真正依赖关系——它们是实体的数据。它不像那些东西提供多态服务等等。我通常不期望依赖注入框架(或 IoC 容器)来创建这样的对象——通常它会是 ORM 或手写代码的一部分。

调用这样的构造函数确实有点痛苦,如果你想提供默认值也变得很棘手。如果您使用的是 C# 4 或更高版本,可选参数和命名参数会有所帮助。(它们确实要求在编译时知道默认值,请注意。)

一种替代方法是创建具有相关默认值的可变构建器类型。我通常把它做成一个嵌套类。您可以给它一个无参数的构造函数,并在构建构建器时验证所需的一切是否存在,或者提供具有所有必需值的构造函数,并将属性保留为可选值。然后你可以使用对象初始化器愉快地创建实例:

var animal = new Animal.Builder("Frederick") {
                 NickName = "Freddie",
                 Weight = 10,
                 MainColor = Color.Brown
             }).Build();

编写构建器是烦人的样板工作,但它可能很有用。如果您发现在构建实例时总是有相关信息可以手头,那么坚持使用当前的构造函数可能会更简单。考虑使用命名参数来使每个参数的含义更清楚,特别是当有多个具有相同类型的参数时:

var animal = new Animal(name: "Frederick", nickname: "Freddie",
                        weight: 10, heightAtWithers: 20,
                        Color.Brown, isMale:true, isAggressive: false);
于 2013-03-21T06:57:11.657 回答
5

IIRC,当 Mark 谈到构造函数过度注入时,它是基于违反SRP的。

一个依赖于大量其他服务的类很可能做不止一件事。
对于依赖于许多原语的类来说,情况不一定如此。

话虽如此,原始数据类型的依赖和“数据持有者类”的数据是两个不同的东西。

将您的类与您链接的文章中描述的类进行比较:
DbChartReader 需要 top能够完成它的工作 - 它是一个依赖项。
Animal不做任何工作。通过构造函数传入的数据基本上就是对象——构造函数的参数就是:data。

于 2013-03-21T06:56:53.510 回答