简介
"用字段替换子类"(Replace Subclass with Fields)重构手法用于简化仅包含常量差异的继承体系。当子类差异仅体现在返回固定值时,应该用父类字段替代子类。
典型代码坏味道
- 子类仅覆盖返回常量的方法
- 子类没有行为差异
- 存在大量只包含工厂方法的子类
- 子类构造函数仅设置固定值
重构步骤
-
识别简单子类
- 找到只返回固定值的子类
- 分析子类的方法差异
- 确认子类没有其他行为
-
提升字段到父类
- 在父类中添加类型标识字段
- 创建包含所有可能值的枚举
- 用字段替代方法返回值
-
调整工厂方法
- 用静态工厂方法替代子类
- 修改客户端创建代码
- 处理遗留的子类引用
-
验证与测试
- 检查所有类型相关逻辑
- 验证字段初始化正确性
- 确保序列化兼容性
示例
重构前:
abstract class BloodType {
abstract String getSymbol();
}
class A extends BloodType {
String getSymbol() {
return "A";
}
}
class B extends BloodType {
String getSymbol() {
return "B";
}
}
重构后:
class BloodType {
private String symbol;
private BloodType(String symbol) {
this.symbol = symbol;
}
public static BloodType A() {
return new BloodType("A");
}
public static BloodType B() {
return new BloodType("B");
}
}
专项练习
基础练习
-
重构行星重力常量
abstract class Planet { abstract double gravity(); } class Earth extends Planet { double gravity() { return 9.8; } } class Mars extends Planet { double gravity() { return 3.7; } }
进阶练习
-
处理国际汇率类型
abstract class Currency { abstract String code(); abstract String symbol(); } class USD extends Currency { String code() { return "USD"; } String symbol() { return "$"; } }
代码审查清单
优势验证
- 类数量减少80%以上
- 消除不必要的类型层次
- 提高代码可维护性
风险提示
- 需要修改工厂方法逻辑
- 可能增加父类复杂度
- 影响现有的instanceof检查