Java 构造函数参数-经验法则

Java 构造函数参数-经验法则,java,design-patterns,refactoring,Java,Design Patterns,Refactoring,通常,类构造函数应接受的最大参数数是多少?我正在开发一个需要大量初始化数据(目前有10个参数)的类。然而,一个有10个参数的构造函数感觉不太对。这让我相信我应该为每一条数据创建一个getter/setter。不幸的是,getter/setter模式并不强制用户输入数据,没有它,对象的特征描述是不完整的,因此是无用的。思维? < P>有很多参数,是时候考虑了。创建一个包含所有这些getter和setter的builder类,使用build()方法返回您真正要构造的类的对象 例子: 在您的客户端代码

通常,类构造函数应接受的最大参数数是多少?我正在开发一个需要大量初始化数据(目前有10个参数)的类。然而,一个有10个参数的构造函数感觉不太对。这让我相信我应该为每一条数据创建一个getter/setter。不幸的是,getter/setter模式并不强制用户输入数据,没有它,对象的特征描述是不完整的,因此是无用的。思维?

< P>有很多参数,是时候考虑了。创建一个包含所有这些getter和setter的builder类,使用build()方法返回您真正要构造的类的对象

例子: 在您的客户端代码中:

ReallyComplicatedClass c = new ReallyComplicatedClass.Builder()
        .int1(myInt1)
        .str2(myStr2)
        .build();

参见[pdf]第7-9页,Josh Bloch在JavaOne 2007上的演讲。(这也是中的第2项,但我手边没有,因此无法引用。)

我建议找到参数之间的依赖关系,然后创建结构或其他类来保留这些参数,并将它们传递给构造函数,而不是一堆乍一看似乎不相关的东西。

您可以决定什么时候足够,并将其用于构造函数(或任何其他方法).

建议对任何方法的七个参数进行相当合理的限制


尝试为某些成员建立合理的默认值。这将允许您使用getter/setter,而不必担心角色描述不完整。

我通常会说,从最开始,不超过五个,并且对程序员的注意力跨度有些悲观。注意:我会将一个列表作为一个实体来计算


如果您确实需要一次性构造对象,通常可以在简单值对象中收集相关参数并将其传递给构造函数。尽量确保值对象具有一定的概念意义,而不仅仅是随机的信息集合

将Param=>Value映射对象传递给构造函数怎么样?如果调用方省略了任何关键参数,则让构造函数抛出异常


这意味着对构造函数的错误调用只会在运行时而不是编译时被捕获,这是一个缺点。但是getter/setter方法也有同样的问题,这应该更容易处理。

我需要更多地了解类的功能和参数,但是有可能类有太多的责任。是否可以将该类划分为更小的独立类

使用setter不能解决类具有许多依赖项/参数的问题。它只是将问题转移到另一个地方,并不强制输入参数

对于方法,我尝试遵循干净代码手册中的建议,每个方法的参数不超过3个(IIRC)。对于构造函数,我可能有更多的参数,因为构造函数通常由依赖项注入框架调用,而不是由我调用

mmyers提到的构建器模式在构建复杂对象时也是一个很好的解决方案,并且没有办法让它们变得不那么复杂。

这取决于具体情况

如果某些参数属于同一类型并且可能混淆,我会容忍一个相当小的数字(比如5)


如果参数是不同类型的,因此不能混淆,那么我可以容忍更多。不过,十将接近极限。

我认为你不能说一个合适的数字是“七,不再”或“五”

构造函数的一个好的经验法则是将对象传递给它的标识,而不是它的状态。您传入的这些参数是对象存在所必需的参数,没有这些参数,对象的大多数操作都不可能进行

<>如果你真的有一个非常复杂的自然身份的班级,因此需要很多参数,然后考虑你的班级的设计。 坏构造函数的一个例子是:

public NightWatchman(int currentFloor, int salary, int hapiness) {...}
public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}
在这里,NightWatchman使用一些默认值构建,这些默认值几乎肯定会在短时间内改变。有趣的是,对象以一种方式被告知它们的值,然后在将来以另一种方式(通过它们的设置器)被告知它们

更好的构造函数示例如下:

public NightWatchman(int currentFloor, int salary, int hapiness) {...}
public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}
守望者正在观察的大门是一个人存在所必需的信息。在课堂上,我会把它标为私人决赛。 我选择将shootOnSight变量传递给构造函数,因为在这里,对象始终知道是否要射杀窃贼是很重要的。在这里,标识被用作类型


我可以有一个名为ShootingGateWatchmanpolicicallinggatewatchman的类,即参数被解释为对象标识的一部分。

但请确保您不仅仅是将复杂性从一个地方转移到另一个地方:包含10个参数的参数对象的构造函数会是什么样子喜欢您的参数对象是否需要参数对象?;-)@本丁:我只是说外面有什么,伙计。坏代码和好代码都可以用它来编写。:)我还将这条规则添加到了我的宗教《代码完成》中。如果您确实使用了生成器模式,那么这也是一个在结果对象上使用最终字段的机会。>/*此处为必需参数*/如果我正确理解了问题,在本例中,所有十个参数都是必需的。因此,构建器模式在这里并没有真正的帮助,因为仍然有一个具有十个参数的构造函数。1+对于“短期记忆规则”,我投赞成票,因为我是询问责任的人。。。这门课肯定做得太多了