3

在我编写的 Java 项目中,我最终使用了在构造函数中被覆盖的方法。就像是:

class SuperClass {
    SuperClass() {
        intialise();
    }

    protected void initialise() {
        //Do some stuff common to all subclasses
        methodA();
        methodB();
    }

    protected abstract void methodA();

    protected abstract void methodB();
}

class SubClass1() {
    SubClass() {
        super();
    }
    protected void methodA() { //Do something }
    protected void methodB() { //Do something }

}

class SubClass2() {
    SubClass() {
        super();
    }
    protected void methodA() { //Do something else }
    protected void methodB() { //Do something else}

}

我现在意识到,虽然在我的情况下它工作得很好,但它有点危险,因为在当前仅构造为 SuperClass 对象的对象上调用了 SubClass 方法(当添加扩展 SuperClass 的新类时可能会忽略这一点)未来)。由于创建对象的方式不同,它在 c++ 中也不起作用。

我能想到解决这个问题的唯一方法是将初始化方法调用向下移动到具体的类构造函数:

   class SuperClass {
    SuperClass() {            
    }

    protected void initialise() {
        methodA();
        methodB();
    }

    protected abstract void methodA();

    protected abstract void methodB();
}

class SubClass1() {
    SubClass() {
        super();
        initialise();
    }
    protected void methodA() { //Do something }
    protected void methodB() { //Do something }

}...

这是解决这个问题的常用方法吗?扩展 SuperClass 的所有其他类都需要记住调用 initialise(),这似乎是一种耻辱(而且很容易忘记)。

我还发现自己在更复杂的情况下做类似的事情,在构造函数中使用工厂方法,它在子类中被覆盖以决定要实现哪个具体类。我能想到的解决这个问题并保持设计模式不变的唯一另一种方法可能是在两阶段过程中构建;即以最低限度构造,然后调用第二种方法来完成工作。

4

4 回答 4

1

需要像这样复杂的初始化的对象确实需要通过工厂方法创建。你确实提到了一个工厂,但是从构造函数中调用,所以这听起来也不是直接的方法。如果你只是在基类中有一个工厂,公开不可见的构造函数,以及一个决定返回哪个具体类的机制,那么该工厂将很容易执行初始化策略。

于 2012-07-20T20:48:24.740 回答
0

这确实不是一个好主意,因为当调用 methodA() 和 methodB() 时,您的子类将无法正确构造。对于扩展课程的人来说,这将是非常混乱的。建议您改用摘要init(),正如 dlev 在他/她的评论中所建议的那样。

于 2012-07-20T19:22:17.077 回答
0

我想知道你是否让事情变得比他们需要的更复杂。

在您的示例中,methodA 的每个实现所做的事情都可以移动到执行该实现的类的构造函数中。因此,不要使用 SubClass::methodA,只需将逻辑移动到 SubClass 构造函数中即可。

如果你这样做,你会以一些可能难以理解的对执行各种初始化位的顺序的控制为代价来获得清晰度。

于 2012-07-20T19:28:19.157 回答
0

Bruce Eckel 在他的“Thinking in Java”中提出的建议是将 SuperClass 类的方法 A() 和方法 B() 设为 final 或私有(隐式为 final),这样即使没有派生类也可以从超类构造函数访问它们访问这些方法,因此不会有危险的覆盖 - 在任何派生类中声明的具有相似签名的任何方法都将只是新方法。

于 2016-07-03T19:39:02.677 回答