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

48 阅读2分钟

简介

"用委托替换子类"是解耦类继承关系的重要重构手法。通过用组合替代继承,可以更灵活地处理类型变化,避免复杂的类层次结构并提高代码的可维护性。

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

  • 子类仅用于改变部分行为
  • 类型变化需要不断创建新子类
  • 存在大量只覆盖单个方法的子类
  • 需要运行时动态改变对象行为

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

  1. 创建委托接口
    • 定义子类差异化方法的接口
    • 声明公共方法签名
  2. 提取委托类
    • 将子类特有逻辑移至委托类
    • 保持原始类的核心逻辑
  3. 建立委托关系
    • 在父类中添加委托引用
    • 通过工厂方法创建组合对象
  4. 移除子类
    • 删除不再需要的子类
    • 迁移客户端代码

示例

重构前代码:

abstract class Animal {
    abstract String makeSound();
}

class Bird extends Animal {
    String makeSound() {
        return "Chirp";
    }
}

class Dog extends Animal {
    String makeSound() {
        return "Bark";
    }
}

重构步骤:

  1. 创建声音行为接口:

    interface SoundBehavior {
        String makeSound();
    }
    
  2. 实现具体行为类:

    class BirdSound implements SoundBehavior {
        public String makeSound() {
            return "Chirp";
        }
    }
    
    class DogSound implements SoundBehavior {
        public String makeSound() {
            return "Bark";
        }
    }
    
  3. 重构Animal类:

    class Animal {
        private SoundBehavior soundBehavior;
    
        Animal(SoundBehavior behavior) {
            this.soundBehavior = behavior;
        }
    
        String makeSound() {
            return soundBehavior.makeSound();
        }
    
        static Animal createBird() {
            return new Animal(new BirdSound());
        }
    
        static Animal createDog() {
            return new Animal(new DogSound());
        }
    }
    

练习

基础练习题

  1. 简单子类替换

    // 重构前
    abstract class Logger {
        abstract void write(String message);
    }
    
    class FileLogger extends Logger {
        void write(String message) {
            // 写入文件
        }
    }
    

进阶练习题

  1. 多行为委托

    // 重构前
    abstract class Payment {
        abstract void process();
    
        abstract void refund();
    }
    

综合拓展练习题

  1. 状态模式重构

    // 重构前
    abstract class OrderState {
        abstract void cancel();
    }
    
    class NewOrderState extends OrderState {
        void cancel() {
            // 新订单取消逻辑
        }
    }
    

代码审查要点

  1. 优点:

    • 减少类层次复杂度
    • 支持运行时行为变更
    • 提高代码复用性
  2. 潜在问题:

    • 避免过度设计简单场景
    • 保持委托接口简洁
    • 注意对象创建成本