继承是面向对象语言的优秀设计理念,但是滥用继承也会导致一些不必要的麻烦。 当我们写代码要继承某个类的是首先要考虑这些东西, · 子类是否需要父类的大部分功能 · 所要写的类是否能通过继承父类来满足需求
因为Java只允许单继承,一旦决定了要继承某个父类,而在多次迭代后发现其实只用了一小部分父类的方法,那时候如果想要修改继承关系就会变的很麻烦。 因此有时候在只需要用到父类的一小部分功能时尽量使用委托来处理。
比较著名的例子是JAVA 1.1 的 java.util.Stack这个类,拿它来做例子。 下面是它的源码
public class Stack<E> extends Vector<E> {
public E push(E item) {
addElement(item);
return item;
}
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
}
这里是简化版的代码。分析代码可以发现,Stack真正需要的只有四个方法,push/pop/size/isEmpty, (思考对LIFO栈的使用场景) 后面两个方法在上面的代码里没有写出来,因为是继承Vector类实现的。 所以实际上 Stack只用到了 Vector的两个方法 isEmpty 和 size,而 push 和 pop 是 Stack 自有的实现。
对于这种情况就属于滥用继承了。因为 Vector 有大量的方法,而 Stack只用到了其中的一小部分。要解决它我们可以用委托的方式来重构这部分代码。
委托和代理模式在思路上差不多一样,不同的是如果以重构为目标的话,我们不需要一个带参构造方法来传入代理对象。直接用private声明就可以了。想了解代理模式的话可以看我之前的推送。 委托代替继承是思路是这样的, 首先构造一个 Vector 对象,
public class Stack<E> {
private Vector vector = new Vector();
然后逐步修改 push和 pop方法,
public E push(E item) {
vector.addElement(item);
return item;
}
public synchronized E pop() {
E obj;
int len = vector.size();
obj = vector.peek();
vector.removeElementAt(len - 1);
return obj;
}
因为之前从Vector继承了 size和 isEmpty,现在在去除了继承关系后我们要手动加上,
public int size() {
return vector.size();
}
public boolean isEmpty() {
return vector.isEmpty();
}
这样就完成了对Stack的重构了。 现在我们可以照常使用 Stack类而不需要修改代码里其他地方对它的引用,同时移除了继承关系, 可以重新按需要让 Stack去继承其他的更合适的父类
====每日沙雕====