我想设计类层次结构。超类有一个抽象方法,子类必须重写这个方法,但我的问题是:这个方法使用超类的数据(实例变量)。
我设计了一些风格来解决这个问题:
样式1:使用私有实例变量并在子类中创建其他实例变量
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...
}
}
哪个更好?或者有更多解决方案来更好地解决我的问题?
答案 0 :(得分:9)
第三种方法通常是首选,如果您设计公共子类,则必须使用。超类希望尽可能多地控制其内部结构。
另一方面,如果您正在开发一个全部位于同一个包中的封闭层次结构,或者至少在同一个项目中,则可以选择将var公开为受保护的,如果有任何好处的话
然而,在子类中复制私有var是所有计数的失败。我想不出任何会对任何事情有帮助的情况。
答案 1 :(得分:1)
恕我直言解决方案#1 很差,因为它不必要地复制了引用,导致混淆(甚至不是内存消耗或一致性)
解决方案#2 和#3 同样出色。如果您使用data
字段final
:
protected final T data;
解决方案#2 是最好的。
答案 2 :(得分:1)
这取决于具体情况。例如,当构造函数传递您需要的数据时,可以使用第一个解决方案。第二个问题是扩展类可以访问字段本身(并且它们可以更改值)。第三种方法是将数据封装在类中。
他们不是一回事。
答案 3 :(得分:1)
我是用户版本2,因为它是最简单的。我尽量让数据最终完成。否则,子类可能会在意外时刻更改数据。
但从个人喜好来看,这些方法并没有多大差别。如果一个变化实际上使它们以某种相关的方式变得不同,那么很容易将一个变为另一个。
当然总有可能会有更好的设计(可能没有继承)潜伏在某个地方,但我们无法从所提供的信息中得知。
评论提示更新:
我经常看到的一个例子是:实现某种策略的子类(B扩展A)。在这些情况下,实际将策略对象作为参数传递给A可能更有意义,它会调用B传入参数的方法。
答案 4 :(得分:1)