构造函数应该有多少个变量?

时间:2009-09-16 17:46:22

标签: c# variables constructor limit

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

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

为了封装类的数据,我将成员声明为private,在构造函数中初始化它们,并使用公共访问器。

以下是一个例子:

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
}

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

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

12 个答案:

答案 0 :(得分:38)

对我来说,正确答案是:

  

您应该传入尽可能多的变量,以便在无效状态下设置对象。

其他任何“选项”,我更喜欢留下属性,特别是现在C#提供对象初始化器。

答案 1 :(得分:34)

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

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

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

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

答案 2 :(得分:5)

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

构造函数参数应包含定义类的依赖项/输入所需的数量。如果该类减少为生命中有一个作业,那么构造函数参数可能是正确的。

答案 3 :(得分:2)

正如其他人所说,对此没有严格的规定,这实际上取决于。 然而,有一个具体的证据表明一个人的大脑可以同时掌握多少东西:这是7 +或 - 2规则。

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

答案 4 :(得分:1)

我喜欢3.5框架......

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

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

答案 5 :(得分:1)

我个人的经验法则是 5

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

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

答案 6 :(得分:0)

特别是由于允许您使用实例化在块中设置变量的较新功能,我倾向于仅在创建时使用参数来创建创建类时 HAVE 的内容,我将基本构造函数设为私有或受保护。

例如,如果你有一个Rectangle类,那么构造函数Rectangle(double width,double height)和使Rectangle()构造函数变为私有可能是有意义的。

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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

这是Martin Fowler的Refactoring书中的气味。这个web page包含指向帮助的标准重构的链接。

在您的情况下,您可能需要考虑一个构建器对象(您可以在其中逐步添加参数和构建器的数字)或参数对象。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

1)明确地称为构造函数

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

另外,如果你知道你的类可能能够处理更多需要更多参数的案例,我会直接使用struct / class。例如:

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

2)隐式调用构造函数

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

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

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

顺便说一下,方法的最大理论参数数量应该足够高,不能达到它:C#Java