编写一个长构造函数有什么缺点吗?

Ara*_*orn 9 oop

它是否会影响加载应用程序的时间?或者这样做的任何其他问题?

pol*_*nts 24

问题是"长"意味着什么含糊不清.以下是一些可能的解释:

解释#1:构造函数有很多参数

具有许多参数的构造函数可能导致可读性差,并且存在更好的替代方案.

以下是Effective Java 2nd Edition的引用,第2项:在面对许多构造函数参数时考虑构建器模式:

传统上,程序员使用了伸缩构造函数模式,其中您只为所需的参数提供构造函数,另一个使用单个可选参数,第三个具有两个可选参数,依此类推......

伸缩构造函数模式基本上是这样的:

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以执行以下任何操作:

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);
Run Code Online (Sandbox Code Playgroud)

但是,您当前不能仅设置nameisAdjustable,并且levels默认情况下保留.您可以提供更多的构造函数重载,但显然数量将爆炸作为参数的数量增长,你甚至可以有多个booleanint参数,这将真正使惹出来的事.

正如你所看到的,这不是一个令人愉快的写作模式,使用起来也不那么令人愉快("真实"在这里意味着什么?13是什么?).

Bloch建议使用构建器模式,这样可以编写类似这样的内容:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();
Run Code Online (Sandbox Code Playgroud)

请注意,现在命名参数,您可以按任何顺序设置它们,并且可以跳过要保留默认值的参数.这肯定比伸缩构造器好得多,特别是当存在大量属于许多相同类型的参数时.

也可以看看

相关问题


解释#2:构造函数做了大量的工作,花费了时间

如果工作必须在构造时完成,那么在构造函数或辅助方法中执行它并不会产生太大的差别.但是,当构造函数将工作委托给辅助方法时,请确保它不可覆盖,因为这可能会导致很多问题.

以下是Effective Java 2nd Edition,第17项:设计和继承文档的引用,或者禁止它:

为了允许继承,类必须遵守一些限制.构造函数不得直接或间接调用可覆盖的方法.如果违反此规则,将导致程序失败.超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法.如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行.

这是一个例子来说明:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}
Run Code Online (Sandbox Code Playgroud)

这里,当Base构造函数调用时overrideMe,Child尚未完成初始化final int x,并且该方法获取错误的值.这几乎肯定会导致错误和错误.


解释#3:构造函数做了很多可以推迟的工作

当某些工作被推迟到实际需要时,可以更快地构建对象; 这称为延迟初始化.例如,当String构造a时,它实际上并不计算其哈希码.它只在首次需要哈希码时才会这样做,然后它会缓存它(因为字符串是不可变的,这个值不会改变).

但是,请考虑Effective Java第2版,第71项:明智地使用延迟初始化.延迟初始化可能会导致细微的错误,并且不会总是产生改进的性能,从而证明增加了复杂性.不要过早优化.

  • 是的,Effective Java是我们的Principia Mathematica.此外,我感到遗憾的是,我只能对你的答案进行一次投票. (2认同)