是什么
保持对象完整(Preserve Whole Object)针对的是「从对象里取出若干字段只为传参」的写法:与其在调用处逐个取值再传进去,不如直接传递对象本身,由被调用方自行取用需要的数据。这样能减少字段级耦合——对象新增字段时不必修改调用链上的每一层。代价与收益需要一起评估:若被调用方因此引入了它本不该依赖的层次,传递对象反而扩大了耦合范围。
识别与做法
| 信号 | 调用处把对象的多个字段拆开传入,例如按下界与上界分别传参 |
|---|---|
| 做法 | 改为传递对象本身,被调方自行取值 |
| 收益 | 减少字段级参数,新增字段时改动范围更小 |
| 权衡 | 评估被调方是否因此与对象所在层次产生了新依赖 |
典型使用场景
- 区间范围判断:把拆分出的上下界改为直接传区间对象
- 订单处理:多处调用都在传客户编号、名称、等级,改为传客户对象
- 统计计算:多个指标函数都从同一条记录取字段,改为接收记录本身
- 配置传递:把零散配置项改为传递配置对象,新增项时不必改签名
- 跨层调用:仅在被调方确实需要该对象语义时传对象,而非仅为了省参数
示例
示例
// 调整前:把区间拆成上下界传入
boolean withinPlan(Plan plan, double low, double high) {
return plan.withinRange(low, high);
}
// 调整后:直接传区间对象,由被调方取值
boolean withinPlan(Plan plan, Range range) {
return plan.withinRange(range);
}传对象还是传字段
| 情形 | 建议 | 理由 |
|---|---|---|
| 调用处只是搬字段 | 传对象 | 减少字段级耦合与重复取值 |
| 被调方与对象不在同一层次 | 传字段或定义精简契约 | 避免引入跨层依赖 |
| 对象携带大量无关字段 | 定义精简的契约对象 | 防止被调方意外依赖无关数据 |
| 对象可变且被调方会写入 | 传不可变副本或只读接口 | 避免读参数变成写参数 |
| 该对象是外部系统模型 | 经适配后传本地契约 | 防止外部结构变化传导到内部 |
传递对象后要防止被调方顺手修改:读参数变成写参数是这类改造最常见的副作用。可以在类型层面提供只读视图,或在文档中明确该参数只读。
对象过大时先考虑拆分:如果被调方只需要其中三四个字段,而对象包含几十个字段,说明这个对象本身承担了过多职责,应先处理它的边界问题。
落地检查清单
- 被调方确实需要该对象的多个字段或整体语义
- 传递后没有跨层或跨模块的新依赖
- 参数保持只读语义,内部状态不被意外修改
- 对象过大时先评估是否需要拆分