构造函数参数 - 经验法则

jav*_*vaj 22 java refactoring design-patterns

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

Mic*_*ers 37

有了这么多参数,就该考虑构建器模式了.使用build()方法创建一个包含所有getter和setter的构建器类,该方法返回您正在尝试构造的类的对象.

例:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的客户端代码中:

ReallyComplicatedClass c = new ReallyComplicatedClass.Builder()
        .int1(myInt1)
        .str2(myStr2)
        .build();
Run Code Online (Sandbox Code Playgroud)

请参阅Effective Java Reloaded [pdf]的第7-9页,Josh Bloch在JavaOne 2007上的演示文稿.(这也是Effective Java 2nd Edition中的第2项,但我没有它,因此我无法引用它.)

  • 如果使用构建器模式,则还可以在结果对象上使用最终字段. (2认同)

Jas*_*yon 12

您可以决定何时足够,并为构造函数(或任何其他方法)使用Introduce Parameter Object.

  • @bendin:我只是说'那里有什么男人.坏的和好的代码都可以用它来编写.:) (2认同)

Gra*_*amS 8

代码完成2建议对任何方法有相当合理的七个参数限制.

尝试为某些成员建立合理的默认值.这将让您使用getter/setter而不必担心表征不完整.


gub*_*bby 5

我认为您不能说一个合适的数字是“七个,没有更多”或“五个”。

构造函数的一个好的经验法则是传递对象的身份,而不是状态。您传入的那些参数对于对象的存在必不可少,如果没有这些参数,则可能无法执行该对象的大多数操作。

如果您确实拥有一个具有非常复杂的自然身份的类,因此需要许多参数,那么请考虑您的类的设计。

不良构造函数的一个示例是:

public NightWatchman(int currentFloor, int salary, int hapiness) {...}
Run Code Online (Sandbox Code Playgroud)

NightWatchman在这里使用一些默认值构建,这些默认值几乎肯定会在短时间内发生变化。有趣的是,该对象以一种方式被告知了它们的值,然后在将来以另一种方式(通过其设置者)使它们具有值。

更好的构造函数的一个示例是:

public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}
Run Code Online (Sandbox Code Playgroud)

守望者正在监视的门是存在必需的信息。在课堂上我将其标记为私人决赛。我选择将ShootOnSight变量传递到构造函数中,因为在这里始终重要的一点是,对象始终知道是否要射击小偷。在这里,身份被用作类型。

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