提炼类(Extract Class)的信号包括:多字段常组合读写、部分字段仅被少数方法访问、类名无法涵盖全部职责、子类化时职责混杂;拆分应明确新类职责、单向委托、渐进搬移、及时测试;收尾需精简接口、重审命名、评估可见性。
当一个类里堆着大量字段,彼此之间逻辑松散、变更节奏不一致,甚至有些字段只在特定方法里成组出现——这说明它已经不是“一个实体”,而是“多个实体挤在同一张身份证上”。提炼类(Extract Class)就是把其中一组高内聚的字段及其相关行为,独立成新类,让每个类真正代表一个清晰、自洽的概念。
什么信号说明该提炼了
以下情况不是孤立存在的,往往同时出现:
多个字段总是一起被读取或修改,比如
officeAreaCode + officeNumber + extension
总是组合使用生成完整电话;
某些字段仅被一小部分方法访问,其余方法完全无视它们;
类名已无法准确概括全部职责,例如叫
,却还管理着地址校验规则、积分计算逻辑、邮件模板渲染等互不相干的事;
想为类添加子类时发现:一部分字段/方法适合继承,另一部分完全不该被子类看到或重写。
怎么拆才不踩坑
提炼不是简单剪切粘贴,关键在于责任边界是否合理、连接是否可控:
先明确新类的职责,给它起一个能表达意图的名字,比如把通信信息抽出来,就叫
;
新类初始只包含字段和私有方法,不对外暴露;旧类持有它的实例,作为委托者统一对外提供接口;
优先搬移底层函数(比如格式化电话、验证邮箱),再搬移调用它们的高层方法;每次搬完立刻编译+运行单元测试;
避免一上来就建双向引用,除非新类确实需要回调旧类的状态。多数情况下单向依赖更安全、更易测试。
拆完还要做三件事
提炼只是开始,收尾动作决定重构是否真正落地:
精简接口
:检查旧类是否还暴露着已被移走字段的 getter/setter,及时删掉或改为委托调用;
重审命名
:如果旧类剩余职责已和原名不符(如抽走所有地址字段后还叫
),就该改名;
评估可见性
:新类是否需要被外部直接构造或修改?若只需内部使用,保持 private;若需复用,再考虑设为 public,并决定它是可变对象还是不可变值对象。
CustomerContactInfoPersonAddress