简介
"用委托替换继承"是解除类耦合的重要重构手法。通过将继承关系改为委托关系,可以消除不必要的"is-a"关系,提高代码灵活性并支持更合理的对象组合。
针对的症状(代码坏味道)
- 子类仅使用父类的部分功能
- 需要复用多个不同类的功能
- 存在违反里氏替换原则的情况
- 父类方法不适合子类需求
用委托替换继承的详细步骤
- 创建委托字段
- 在子类中添加父类类型的字段
- 初始化委托对象实例
- 建立委托方法
- 为需要的方法创建转发方法
- 将super调用改为委托对象调用
- 移除继承关系
- 删除extends声明
- 处理构造方法初始化
- 清理残留方法
- 重写不需要的父类方法
- 添加缺失的必要方法
示例
重构前代码:
class MyStack<E> extends Vector<E> {
public void push(E element) {
addElement(element);
}
public E pop() {
E obj = peek();
removeElementAt(size() - 1);
return obj;
}
}
重构后代码:
class MyStack<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();
}
public int size() {
return elements.size();
}
}
练习
基础练习题
-
简单继承替换
// 重构前 class AuditLogger extends FileWriter { void logAction(String action) { write("ACTION: " + action); } }
进阶练习题
-
多方法委托
// 重构前 class CachedEmployee extends Employee { // 需要缓存功能 }
综合拓展练习题
-
多重委托
// 重构前 class HybridDataSource extends DatabaseDataSource { // 需要文件和数据源功能 }
代码审查要点
-
优点:
- 解除不必要的耦合
- 精确控制暴露接口
- 支持动态组合功能
-
潜在问题:
- 保持委托方法一致性
- 注意对象生命周期管理
- 避免过度委托导致复杂度