我意识到这是一个非常开放的问题,可以得到各种各样的答案,但这里有。
使用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个变量传递给子类的构造函数时,我开始质疑我的设计,但是我也很难找到一种不同的方法来实现这一点。
这被认为是不好的编程习惯吗?您应该传递给构造函数的变量数量是否有一般限制?
答案 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的答案中找到。