简介
"用委托替换子类"是解耦类继承关系的重要重构手法。通过用组合替代继承,可以更灵活地处理类型变化,避免复杂的类层次结构并提高代码的可维护性。
针对的症状(代码坏味道)
- 子类仅用于改变部分行为
- 类型变化需要不断创建新子类
- 存在大量只覆盖单个方法的子类
- 需要运行时动态改变对象行为
用委托替换子类的详细步骤
- 创建委托接口
- 定义子类差异化方法的接口
- 声明公共方法签名
- 提取委托类
- 将子类特有逻辑移至委托类
- 保持原始类的核心逻辑
- 建立委托关系
- 在父类中添加委托引用
- 通过工厂方法创建组合对象
- 移除子类
- 删除不再需要的子类
- 迁移客户端代码
示例
重构前代码:
abstract class Animal {
abstract String makeSound();
}
class Bird extends Animal {
String makeSound() {
return "Chirp";
}
}
class Dog extends Animal {
String makeSound() {
return "Bark";
}
}
重构步骤:
-
创建声音行为接口:
interface SoundBehavior { String makeSound(); } -
实现具体行为类:
class BirdSound implements SoundBehavior { public String makeSound() { return "Chirp"; } } class DogSound implements SoundBehavior { public String makeSound() { return "Bark"; } } -
重构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()); } }
练习
基础练习题
-
简单子类替换
// 重构前 abstract class Logger { abstract void write(String message); } class FileLogger extends Logger { void write(String message) { // 写入文件 } }
进阶练习题
-
多行为委托
// 重构前 abstract class Payment { abstract void process(); abstract void refund(); }
综合拓展练习题
-
状态模式重构
// 重构前 abstract class OrderState { abstract void cancel(); } class NewOrderState extends OrderState { void cancel() { // 新订单取消逻辑 } }
代码审查要点
-
优点:
- 减少类层次复杂度
- 支持运行时行为变更
- 提高代码复用性
-
潜在问题:
- 避免过度设计简单场景
- 保持委托接口简洁
- 注意对象创建成本