简介
"用委托替换超类"是解除错误继承关系的有效重构手法。通过用组合替代继承,可以避免不合理的"is-a"关系,提高代码灵活性并减少父类耦合。
针对的症状(代码坏味道)
- 子类仅使用父类的部分功能
- 需要复用多个不同类的功能
- 父类包含子类不需要的方法
- 存在违反LSP原则的继承关系
用委托替换超类的详细步骤
- 创建委托字段
- 在子类中添加超类类型的字段
- 初始化委托对象实例
- 迁移方法调用
- 将super调用改为委托对象调用
- 重写不需要的方法实现
- 移除继承关系
- 删除extends声明
- 处理构造方法初始化
- 调整客户端代码
- 替换向上转型的引用
- 保持接口兼容性
示例
重构前代码:
class Stack<E> extends Vector<E> {
public void push(E element) {
addElement(element);
}
public E pop() {
E obj = peek();
removeElementAt(size() - 1);
return obj;
}
}
重构步骤:
-
添加Vector委托:
class Stack<E> { private Vector<E> elements = new Vector<>(); public void push(E element) { elements.addElement(element); } public E pop() { E obj = peek(); elements.removeElementAt(elements.size() - 1); return obj; } // 保留需要的方法 public E peek() { return elements.lastElement(); } }
练习
基础练习题
-
简单超类委托
// 重构前 class MyList extends ArrayList<String> { void specialAdd(String item) { if (!contains(item)) { super.add(item); } } }
进阶练习题
-
多方法委托
// 重构前 class AuditLogger extends FileWriter { void logAction(String action) { write("ACTION: " + action); } }
综合拓展练习题
-
复合委托关系
// 重构前 class CachedDataSource extends DatabaseDataSource { // 同时需要缓存功能和数据源功能 }
代码审查要点
-
优点:
- 解除错误继承链
- 精确控制暴露方法
- 支持多对象组合
-
潜在问题:
- 保持委托方法一致性
- 处理接口兼容问题
- 注意对象生命周期管理