首页/开发/代码质量与评审速查/坏味道:中间人(Middle Man)
重构手法62 条

坏味道:中间人(Middle Man)

类的大部分方法只是转发给另一个对象:用 Remove Middle Man、Inline Class 削减多余委托;封装与转发之间要找平衡点,而不是谁转发谁就坏。

中间人坏味道是什么

类的大部分方法只是把调用转发给另一个对象:方法体一行,参数原样传递,返回值直接返回。这类转发层层叠加后,读代码要跨越多个同名不同层的方法,改动也要跟着穿透。它与过长的消息链是同一问题的两个极端——链太长要封装,封装过头又成了中间人。

基本信息

信号超过一半方法是一行转发
手法Remove Middle Man、Inline Class
对照与 Hide Delegate 是相反方向的拉锯
判断标准转发方法是否携带额外语义

判断与处理

  • 转发方法没有任何附加逻辑:校验、组合、转换都不做,只是原样转交
  • 类名与职责说不清:既不是领域概念,也不做协调
  • 调用方总是越过它直接拿到内层对象:说明它没有提供额外价值
  • 转发带来的价值是隔离变化来源:接口为多实现准备,即使当前只有一个实现也值得保留
  • 转发方法承担了校验或事务语义:不要删,反而应当把这类职责集中
  • 只是为了让类看起来完整而补齐的一批同名方法:这类最该内联

内联方向

内联方向
// 之前:Account 的每个方法都在转给 ledger
class Account {
    double balance() { return this.ledger.balance(); }
    double total()   { return this.ledger.total(); }
    Date openedAt()  { return this.ledger.openedAt(); }
}

// 之后:依赖方向清晰时直接持有 ledger
class Report {
    private final Ledger ledger;      // 由容器注入
    double balance() { return ledger.balance(); }
}

// 保留转发的情况:转发里带了计算或校验
public double available() {
    return ledger.balance() - ledger.holds();   // 有计算,属于服务而非噪音
}

保留还是内联

情况处理理由
纯转发、无校验无组合内联只增加跳转,不提供价值
转发含校验或事务语义保留职责集中在此处
接口为多实现准备保留隔离变化,替换实现不动调用方
调用方总要绕过它内联说明封装没有形成有效边界
为减转发直接暴露内部依赖会破坏原有边界:如果那个依赖是基础设施细节,调用方从此与存储或协议绑在一起,后续替换成本反而更高。内联前先确认依赖方向本身是稳定的。
把有校验职责的转发当噪音删掉,校验逻辑会随之丢失——这是内联中最容易犯的错误。删除前把每个转发方法的实现读一遍,别只看方法签名。

易错点

  • 为减转发直接暴露内部依赖:破坏了原有边界,调用方与实现细节绑定
  • 把有校验职责的转发当噪音删掉:校验逻辑随之丢失,缺陷在边界处出现
  • 反向过度封装成 Hide Delegate:两个方向来回改,结构越来越绕
  • 删除转发后不同步更新调用方:部分调用点仍走旧路径,两套入口并存

数据来源与参考

  • 《重构》第 2 版 · 第 3 章(Middle Man)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌