4

我想设计类层次结构。超类有一个抽象方法,子类必须重写这个方法,但我的问题是:这个方法使用超类的数据(实例变量)。

我设计了一些样式来解决这个问题:

风格一:使用私有实例变量并在子类中创建其他实例变量

class SuperClass {
    private T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();
}

class SubClass extends SuperClass {
    private T data; // use another variable

    public SubClass(T data) {
        super(data);
        this.data = data;
    }

    public void doSomething() {
        // use 'data'
        int length = data.getLength(); // for example...
    }
}

样式 2:使用受保护的实例变量:

class SuperClass {
    protected T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();
}

class SubClass extends SuperClass {
    public void doSomething() {
        // use 'data'
        int length = data.getLength(); // for example...
    }
}

风格 3:使用私有实例变量和受保护方法:

class SuperClass {
    private T data;

    public SuperClass(T data) { /* ... */}

    public abstract void doSomething();

    protected T getData() {
        return data;
    }
}

class SubClass extends SuperClass {
    public void doSomething() {
        // use 'data'
        int length = getData.getLength(); // for example...
    }
}

他们哪个更好?或者有更多的解决方案来更好地解决我的问题?

4

5 回答 5

9

第三种方法通常是首选,如果您为公共子类设计,则必须这样做。超类希望尽可能多地控制其内部。

另一方面,如果您正在开发一个封闭的层次结构,它都在同一个包中,或者至少都在同一个项目中,如果有任何好处,您可以选择将 var 公开为受保护的。

但是,在子类中复制私有 var 无论如何都是失败的。我想不出任何有帮助的情况。

于 2012-07-09T19:39:02.397 回答
1

恕我直言,解决方案#1很差,因为它不必要地复制了引用,导致混淆(甚至与内存消耗或一致性无关)

解决方案#2#3同样好。如果你让你的data领域final

protected final T data;

解决方案#2是你能得到的最好的。

于 2012-07-09T19:39:24.753 回答
1

这取决于实际情况。例如,第一个解决方案可以仅在您需要的数据由构造函数传递时使用。第二个问题是扩展类可以访问字段本身(并且它们可以更改值)。第三种是将数据封装在类中的方法。

  1. 如果您需要更改子类上的字段,您可以使用方法 2;
  2. 如果您有数据作为构造函数,则方法 1;
  3. 如果您只需要公开但保留封装的详细信息,请使用方法 3。

他们不是一回事。

于 2012-07-09T19:39:55.787 回答
1

我会使用第 2 版,因为它是最简单的。不过,我会尝试使数据最终确定。否则子类可能会在意想不到的时刻改变数据。

但除了个人喜好,这些方法差别不大。而且,如果发生的更改实际上使它们以某种相关方式有所不同,则很容易将其中一个重构为其他。

当然,总有一些更好的设计(可能根本没有继承)潜伏在某个地方的可能性,但我们无法从提供的信息中判断出来。

评论提示更新:

我经常看到的一个例子是:实现某种策略的子类(B 扩展 A)。在这些情况下,将策略对象作为参数实际传递给 A 可能更有意义,A 调用 B 的方法传入参数。

于 2012-07-09T19:40:32.257 回答
1
  • Style1 : SuperClass.data 和 SubClass.data 是两个不同的变量,因此不能保证它们会引用同一个对象。
  • Style2 :这会很好,但 SubClass 可以更改 SuperClass 变量的引用 - 例如。可以将变量设置为null。不清楚谁 - 哪些类 - 更新了变量。
  • Style3 :我认为这是最好的方式,因为 SuperClass 真正封装和控制对成员变量的访问。
    我们还可以使 getData() 方法成为最终方法,这样设计就不会被滥用。
于 2012-07-09T19:50:36.997 回答