什么是依恋情结
依恋情结指某个函数频繁访问另一个对象的内部数据,访问别的对象比访问自己所在对象还多。这通常说明职责放错了位置:数据和行为分了家。处方是用移动函数把方法搬到它真正依赖的数据所在的类里,让数据与行为待在一起,调用方依赖也随之变少。
基本信息
| 典型信号 | 函数里别的对象前缀出现次数超过自身 |
|---|---|
| 处方 | 移动函数,移动后删除原方法 |
| 例外情况 | 策略、访问者等模式中有意为之的分离 |
| 相邻问题 | 数据泥团、基本类型偏执常同时出现 |
| 收益 | 职责归位,调用方依赖变少 |
典型使用场景
- 工具类里塞满对某个实体字段的计算逻辑
- 服务方法中大部分代码在读写另一个对象的属性
- 转换方法只读取另一个对象的数据,自己几乎没有状态
- 表单校验写在控制器里,但字段与规则都属于领域对象
- 报表汇总逻辑放在与数据完全无关的模块
移动前后
移动前后
// 之前:total 依赖 Purchase 的内部数据,却不在 Purchase 里
double total(Purchase p) {
return p.items().stream().mapToDouble(Item::price).sum();
}
// 之后:搬到数据所在的地方
class Purchase {
double total() { return items.stream().mapToDouble(Item::price).sum(); }
}
// 调用方从 total(p) 变为 p.total(),原方法删除信号与判断
| 信号 | 含义 | 处理 |
|---|---|---|
| 访问别的对象多于自身 | 职责放错了位置 | 把方法移动到数据所在类 |
| 只用到对方一两个字段 | 耦合面很窄 | 考虑直接传参而不是传整个对象 |
| 多个函数都依恋同一对象 | 该对象的职责被外置 | 集中搬回该对象 |
例外情况要说清楚:策略、访问者、双重分发等模式里,行为与数据的分离是刻意的。判断的关键在于,这是有意设计还是长期演化出的错位。
移动后保留一个转发方法会让调用链变长、排查困难;如果确实需要兼容期,写明原因与后续删除计划。