java 构造函数参数 - 经验法则
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/730201/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Constructor Parameters - Rule of Thumb
提问by javacavaj
In general, what is the maximum number of parameters a class constructor should accept? I'm developing a class that requires a lot of initialization data (currently 10 parameters). However, a constructor with 10 parameters doesn't feel right. That leads me to believe I should create a getter/setter for each piece of data. Unfortunately, the getter/setter pattern doesn't force the user to enter the data and without it characterization of the object is incomplete and therefore useless. Thoughts?
一般来说,类构造函数应该接受的最大参数数是多少?我正在开发一个需要大量初始化数据(目前有 10 个参数)的类。但是,带有 10 个参数的构造函数感觉不对。这让我相信我应该为每条数据创建一个 getter/setter。不幸的是,getter/setter 模式不会强制用户输入数据,如果没有它,对象的特征是不完整的,因此是无用的。想法?
回答by Michael Myers
With that many parameters, it's time to consider the Builder pattern. Create a builder class which contains all of those getters and setters, with a build() method that returns an object of the class that you're really trying to construct.
有了这么多参数,是时候考虑Builder 模式了。创建一个包含所有这些 getter 和 setter 的构建器类,使用 build() 方法返回您真正尝试构造的类的对象。
Example:
例子:
public class ReallyComplicatedClass {
private int int1;
private int int2;
private String str1;
private String str2;
// ... and so on
// Note that the constructor is private
private ReallyComplicatedClass(Builder builder) {
// set all those variables from the builder
}
public static class Builder {
private int int1;
private int int2;
private String str1;
private String str2;
// and so on
public Builder(/* required parameters here */) {
// set required parameters
}
public Builder int1(int newInt) {
int1 = newInt;
return this;
}
// ... setters for all optional parameters, all returning 'this'
public ReallyComplicatedClass build() {
return new ReallyComplicatedClass(this);
}
}
}
And in your client code:
在您的客户端代码中:
ReallyComplicatedClass c = new ReallyComplicatedClass.Builder()
.int1(myInt1)
.str2(myStr2)
.build();
See pages 7-9 of Effective Java Reloaded[pdf], Josh Bloch's presentation at JavaOne 2007. (This is also item 2 in Effective Java 2nd Edition, but I don't have it handy so I can't quote from it.)
请参阅Effective Java Reloaded[pdf] 的第 7-9 页,Josh Bloch 在 JavaOne 2007 上的演讲。(这也是Effective Java 2nd Edition中的第 2 项,但我手边没有它,所以我无法引用它。)
回答by Jason Punyon
You can decide when enough is enough and use Introduce Parameter Objectfor your constructor (or any other method for that matter).
您可以决定何时足够,并为您的构造函数(或任何其他方法)使用Introduce Parameter Object。
回答by GrahamS
Code Complete 2recommends a fairly sensible limit of seven parameters to any method.
Code Complete 2建议将任何方法的七个参数限制为一个相当合理的限制。
Try to establish sensible default values for some of the members. This will let you use getter/setters without worrying that the characterization is incomplete.
尝试为某些成员建立合理的默认值。这将使您可以使用 getter/setter,而不必担心特征描述不完整。
回答by gubby
I don't think you can say that an appropriate number is "seven, no more" or "five".
我认为你不能说合适的数字是“七,不多了”或“五”。
A good rule of thumb for constructors is to pass an object its identity, not its state. Those parameters you pass in are ones that are essential for the existence of the object, and without which most operations of the object may not be possible.
构造函数的一个很好的经验法则是传递一个对象的身份,而不是它的状态。您传入的那些参数对于对象的存在是必不可少的,没有这些参数,对象的大多数操作都可能无法进行。
If you genuinely have a class with a very complicated natural identity, hence requiring many parameters then consider the design of your class.
如果您真的有一个具有非常复杂的自然身份的类,因此需要许多参数,那么请考虑您的类的设计。
An example of a bad constructor is:
错误构造函数的一个例子是:
public NightWatchman(int currentFloor, int salary, int hapiness) {...}
Here the NightWatchman is being constructed with some default values that will almost certainly change in a short time. It seems funny that the object is told about their values one way, and then has them in a different way (via their setters) in future.
在这里,NightWatchman 正在使用一些默认值构建,这些默认值几乎肯定会在短时间内发生变化。有趣的是,对象以一种方式被告知它们的值,然后在未来以不同的方式(通过它们的 setter)拥有它们。
An example of a better constructor is:
一个更好的构造函数的例子是:
public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}
The gate the watchman is watching is required information for one to exist. In the class I would mark it private final. I've chosen to pass the shootOnSightvariable into the constructor, because here it was important that at all times the object knew whether to shoot burglars. Here, identity is being used as type.
守望者正在观看的大门是一个人存在的必要信息。在课堂上,我会将其标记为private final。我选择将shotOnSight变量传递给构造函数,因为在这里,对象始终知道是否射击窃贼很重要。在这里,身份被用作类型。
I could have a class called ShootingGateWatchmanand PoliceCallingGateWatchman- i.e the parameter is interpreted as part of the objects identity.
我可以有一个名为ShootingGateWatchman和PoliceCallingGateWatchman的类- 即参数被解释为对象标识的一部分。
回答by Konstantinos
i would suggest to find dependencies between the parameters and then create structures or otherwise classes to keep those and pass them to your constructor instead of a bunch of things that don't seem related at first glance.
我建议找到参数之间的依赖关系,然后创建结构或其他类来保留它们并将它们传递给您的构造函数,而不是一堆乍一看似乎不相关的东西。
回答by Esko Luontola
I would need to know more that what the class does and what the parameters are, but there is a possibility that the class has too many responsibilities. Would it be possible to split the class to smaller independent classes?
我需要更多地了解该类的作用以及参数是什么,但该类有可能承担太多责任。是否可以将班级拆分为较小的独立班级?
Using setters does not solve the problem of the class having many dependencies/parameters. It just moves the problem to a different place and does not force the parameters being entered.
使用 setter 并不能解决类具有许多依赖项/参数的问题。它只是将问题移到不同的地方,并不强制输入参数。
For methods, I try to follow the advice from the Clean Code book to have no more than 3 parameters per method (IIRC). For constructors I may have more parameters, because typically the constructor will be called by my dependency injection framework and not by me.
对于方法,我尝试遵循 Clean Code 手册中的建议,每个方法 (IIRC) 的参数不超过 3 个。对于构造函数,我可能有更多参数,因为通常构造函数将由我的依赖注入框架而不是我调用。
The builder pattern mentioned by mmyers is also a good solution when building complex objects, and there is no way to make them less complex.
mmyers 提到的builder模式在构建复杂对象时也是一个很好的解决方案,没有办法让它们变得不那么复杂。
回答by Pontus Gagge
I'd usually say no more than five, from the 7+/-2 rule of short term memory, and some pessimism about programmer attention spans. Note: I'd count a varargslist as one entity.
我通常会说不超过五个,根据短期记忆的7+/-2 规则,以及对程序员注意力跨度的一些悲观主义。注意:我会将可变参数列表视为一个实体。
If you really are constrained to construct the object in one go, you can usually collect related parameters in simple value objects and pass those into the constructor. Try to ensure that the value objects make some conceptual sense and are not just random collections of information...
如果你真的被限制一次构造对象,你通常可以在简单的值对象中收集相关参数并将它们传递给构造函数。尽量确保值对象具有一定的概念意义,而不仅仅是信息的随机集合......
回答by starblue
It depends.
这取决于。
If some parameters are of the same type and can be mixed up, I'd tolerate a rather small number (say 5).
如果某些参数属于相同类型并且可以混淆,我会容忍一个相当小的数字(比如 5)。
If the parameters are of different types, so they cannot be mixed up, then I'd tolerate some more. Ten would be close to the limit, though.
如果参数的类型不同,不能混淆,那我就容忍一些。不过,十个将接近极限。
回答by BlairHippo
How about passing in a Param => Value Map object to the constructor? If the caller omits any critical params, have the constructor toss an Exception.
将 Param => Value Map 对象传递给构造函数怎么样?如果调用者省略了任何关键参数,则让构造函数抛出异常。
It means bad calls to the constructor will only be caught at runtime instead of compile time, which is a downside. But a getter/setter approach has the same problem, and this should be much easier to work with.
这意味着对构造函数的错误调用只会在运行时而不是编译时被捕获,这是一个缺点。但是 getter/setter 方法也有同样的问题,这应该更容易使用。

