重构手法——函数行为重塑类 | 语意 | 用委托替换超类

49 阅读2分钟

简介

"用委托替换超类"是解除错误继承关系的有效重构手法。通过用组合替代继承,可以避免不合理的"is-a"关系,提高代码灵活性并减少父类耦合。

针对的症状(代码坏味道)

  • 子类仅使用父类的部分功能
  • 需要复用多个不同类的功能
  • 父类包含子类不需要的方法
  • 存在违反LSP原则的继承关系

用委托替换超类的详细步骤

  1. 创建委托字段
    • 在子类中添加超类类型的字段
    • 初始化委托对象实例
  2. 迁移方法调用
    • 将super调用改为委托对象调用
    • 重写不需要的方法实现
  3. 移除继承关系
    • 删除extends声明
    • 处理构造方法初始化
  4. 调整客户端代码
    • 替换向上转型的引用
    • 保持接口兼容性

示例

重构前代码:

class Stack<E> extends Vector<E> {
    public void push(E element) {
        addElement(element);
    }

    public E pop() {
        E obj = peek();
        removeElementAt(size() - 1);
        return obj;
    }
}

重构步骤:

  1. 添加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();
        }
    }
    

练习

基础练习题

  1. 简单超类委托

    // 重构前
    class MyList extends ArrayList<String> {
        void specialAdd(String item) {
            if (!contains(item)) {
                super.add(item);
            }
        }
    }
    

进阶练习题

  1. 多方法委托

    // 重构前
    class AuditLogger extends FileWriter {
        void logAction(String action) {
            write("ACTION: " + action);
        }
    }
    

综合拓展练习题

  1. 复合委托关系

    // 重构前
    class CachedDataSource extends DatabaseDataSource {
        // 同时需要缓存功能和数据源功能
    }
    

代码审查要点

  1. 优点:

    • 解除错误继承链
    • 精确控制暴露方法
    • 支持多对象组合
  2. 潜在问题:

    • 保持委托方法一致性
    • 处理接口兼容问题
    • 注意对象生命周期管理