32

我意识到这是一个非常开放的问题,可以得到各种各样的答案,但这里有。

使用 C#(或 Java,或任何 OO 语言),是否有一般规则规定应将多少变量传递给构造函数?我传递给扩展类的构造函数的变量数量似乎失控了。

为了封装类的数据,我将成员声明为私有,在构造函数中对其进行初始化,并使用公共访问器。

这是一个例子:

public class A
{
  private int var1;
  private int var2;
  private int var3;

  //3 variables passed in
  public A(int v1, int v2, int v3)
  {
    var1 = v1;
    var2 = v2;
    var3 = v3;
  }

  //Properties (accessors) here
}

public class B : A
{
  private int var4;
  private int var5;

  //5 variables passed in
  public B(int v1, int v2, int v3, int v4, int v5)
  : base(v1,v2,v3)
  {
    var4 = v4;
    var5 = v5;
  }

  //Properties (accessors) here
}

public class C : B
{
  private int var6;
  private int var7;

  //7 variables passed in !!!
  public C(int v1, int v2, int v3, int v4, int v5, int v6, int v7)
  : base(v1,v2,v3,v4,v5)
  {
    var6 = v6;
    var7 = v7;
  }

  //Properties (accessors) here
}

我的构造函数通常传入不同的对象,而不仅仅是整数。当我开始将 7 个变量传递给子类的构造函数时,我开始质疑我的设计,但我也很难找到一种不同的方法来做到这一点。

这被认为是不好的编程习惯吗?您应该传递给构造函数的变量数量是否有一般限制?

4

12 回答 12

38

对我来说,正确答案是:

您应该传入尽可能多的变量,以将对象设置为非无效状态。

其他任何“选项”,我更喜欢保留为属性,尤其是现在 C# 提供了对象初始值设定项。

于 2009-09-16T17:51:49.300 回答
34

一般来说,我发现如果超过 3 个,那就是对设计进行快速健全性检查的标志。如果超过 5 个,这是一个重大警告,表明设计可能有问题。

但是,请注意“可能”这个词 - 最后,唯一真正的规则是使用尽可能多的功能来发挥作用,不多也不少。总是有例外和情况,其中更多参数最有意义。

如果参数以某种方式相关,则应将它们封装到容器类中。

如果参数不相关——例如,将它们分组到容器类中是没有意义的——你的类可能做的事情太多了。通常没有理由一个班级应该知道 7 条完全不同的信息。将您的班级分成不同的班级。例如,将参数 3 和 4 委托给子类,将参数 5、6 和 7 委托给另一个类可能是有意义的——而您的父类只是协调它们之间的操作。

于 2009-09-16T17:49:21.370 回答
5

很难给“太多”一个硬性、快速的数字。真正的问题是:你的班级在做什么?班级做的太多了吗?如果是这样,是时候将课程分成更小、更简洁的课程了。

构造函数参数应包括定义类的依赖项/输入所需的数量。如果该类被简化为一生只有一份工作,那么您的构造函数参数可能是正确的。

于 2009-09-16T17:50:57.170 回答
2

正如其他人所说,这没有硬性规定,这真的取决于。然而,有具体的证据表明一个人的大脑可以一次掌握多少东西:这就是 7 + 或 - 2 规则。

这类问题在 Steve McConnell 的 Code Complete 中得到了很好的回答。如果你还没有读过这本书,我建议你读一读。

于 2009-09-16T17:56:45.800 回答
1

我喜欢 3.5 框架的一件事......

new Foo {
    Street = "909 Rose Ave",
    City = "San Diego",
    State = "CA",
    FName = "Joe",
    LName = "Wazowski",
    ID = "987665454"
};

不用再担心构造函数太多,或者构造函数太多,参数太多。

于 2009-09-16T17:58:51.440 回答
1

我个人的经验法则是5

如果您需要更多,请将它们包装在结构或对象中。

您不必初始化对象时,这会发生变化。如果我使用 IOC 容器初始化对象,则构造参数的数量基本上是无限的。

于 2009-09-16T18:39:12.500 回答
0

特别是由于允许您通过实例化在块中设置变量的较新功能,我倾向于仅在创建类时使用必须设置的参数在这种情况下,我将基本构造函数设为私有或受保护.

例如,如果您有一个 Rectangle 类,则将构造函数 Rectangle(double width, double height) 设为私有,并将 Rectangle() 构造函数设为私有可能是有意义的。

于 2009-09-16T17:53:30.457 回答
0

此外,如果你认为你的类应该只通过构造函数设置它的属性值,你可以放置一个无参数的私有构造函数。

于 2009-09-16T17:54:51.983 回答
0

一旦难以记住如何使用它们,系统就会有太多参数。如果它们都是整数,则 3 太多了。如果它们是不同的类型,您可以拥有更多。

这是 Martin Fowler 的重构书中的味道。此网页包含指向有帮助的标准重构的链接。

在您的情况下,您可能需要考虑一个构建器对象(您可以在其中逐渐添加参数并且构建器计算出类)或参数对象。

于 2009-09-16T17:56:46.877 回答
0

恕我直言,使用 TDD 是评估此问题的有用视角。一旦你的 ctor 难以应用于单元测试 ctor 或 SetUp(),那么初始化/工厂的参数太多并且相对太紧耦合。

于 2009-09-16T19:40:23.563 回答
0

您需要传入构造类所需的所有内容。当我发现自己传递了很多变量时,我经常做的是为包含构造它所需信息的对象创建一个“配置”类,并将其传递给构造函数。它极大地简化了实例化对象并使设计更简洁。

于 2009-09-16T20:01:47.900 回答
0

我将尝试从不同的角度回答这个问题。我看到了使用构造函数的两种主要方式,所以有两种方式来思考有多少参数太多了。

1) 显式调用构造函数

这是您“新建”对象的经典方法,您必须指定所有必需的参数值。此处的其他答案已完全涵盖了这一点。我个人的经验法则是:所有参数都应该放在一行上,所以我最多有 3-4 个参数。

另外,如果你知道你的类将来可能能够处理更多需要更多参数的情况,我会直接使用结构/类。例如:

假设一个类应该根据某些标准处理一些对象过滤。一开始,只有2-3个标准。知道它将来可能有更多的标准,我会直接从一开始就发送一个 FilterValue 对象。

2) 隐式调用构造函数

一个典型的案例是使用依赖注入。在几乎所有情况下,所有构造函数参数都被注入,因此为您构建对象是 DI 框架的业务。

在这里,“常识”不适用,因为可以根据需要注入尽可能多的服务。例如:

如果使用聚合来自任意数量存储库的更改的工作单元模式执行数据持久性,则工作单元类将被注入所有使用的存储库。更多详细信息可以在CodeReview的这个答案中找到。

顺便说一句,方法的最大理论参数数量应该足够高,以至于永远不会达到它:C#Java

于 2016-12-30T15:55:41.027 回答