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

时间:2010-06-03 05:56:55

标签: oop

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

7 个答案:

答案 0 :(得分:24)

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

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

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

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

  

传统上,程序员使用 telescoping构造函数模式,在该模式中,您只提供构造函数所需的参数,另一个使用单个可选参数,第三个使用两个可选参数,依此类推。 ..

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

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;
    }
}

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

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);

但是,您目前无法仅设置nameisAdjustable,并且默认保留levels。你可以提供更多的构造函数重载,但显然随着参数数量的增加,数字会爆炸,你甚至可能有多个booleanint参数,这实际上会让事情搞得一团糟。 / p>

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

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

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();

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

另见

相关问题


解释#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"
    }
}

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


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

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

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

答案 1 :(得分:1)

构造函数有点特殊,因为构造函数中的未处理异常可能会产生奇怪的副作用。在没有看到你的代码的情况下,我会假设一个长构造函数会增加异常的风险。我会使构造函数尽可能简单,并利用其他方法来完成其余的工作,以便提供更好的错误处理。

答案 2 :(得分:1)

最大的缺点可能与编写任何其他长函数相同 - 它可能变得复杂且难以理解。

其余的将会有所不同。首先,长度和执行时间不一定相关 - 你可能有一行(例如,函数调用)需要几秒钟才能完成(例如,连接到服务器)或许多代码完全在CPU并快速完成。

启动时间(显然)仅受启动期间调用的构造函数的影响。我在编写的任何代码中都没有遇到过这个问题(最近都是这样),但是我看到了代码。在某些类型的嵌入式系统(例如)中,您确实希望避免在正常使用期间创建和销毁对象,因此您可以在启动期间静态创建几乎所有内容。一旦运行,您可以将所有处理器时间用于完成实际工作。

答案 3 :(得分:0)

构造函数是另一个功能。您需要多次调用非常长的函数才能使程序运行缓慢。因此,如果它只被调用一次通常无关紧要内部代码。

答案 4 :(得分:0)

它自然会影响构造该对象所花费的时间,但仅仅是拥有一个空构造函数并调用方法来代替它。它对应用程序加载时间没有影响

答案 5 :(得分:0)

在复制构造函数的情况下,如果在那种情况下使用donot use reference 它将创建一个对象并调用复制构造函数并传递 复制构造函数的值以及每次创建新对象时的值 每次它将调用复制构造函数,它将无限和 填充内存然后显示错误信息。

如果我们传递引用,它将不会创建用于存储的新对象 价值。并且不会发生递归

答案 6 :(得分:0)

我会避免在你的构造函数中做任何不必要的事情。在那里初始化你的变量,尽量不要做太多其他事情。其他功能应该驻留在您需要时调用的单独函数中。