首页/开发/代码质量与评审速查/ISP 实操:从调用方绘制角色接口
设计原则与模式62 条

ISP 实操:从调用方绘制角色接口

画接口前先画调用方:列出每个使用场景真正需要的方法集合,合并同类使用场景,得到角色接口;实现类按需实现多个角色,接口之间可再组合。

接口隔离的实操顺序

接口隔离原则常被表述为「不该强迫调用方依赖它不使用的方法」,实操时更有效的方式是从调用方反推接口:先列出每个使用场景真正需要的方法集合,把同类场景合并,得到一组角色接口。实现类按能力实现多个角色,调用方只依赖它需要的那个角色。判断做得好不好,看每个实现类是否还存在被迫写出的空方法或抛异常方法。

实操路径

起点调用方需求清单,按使用场景逐条列出
产物角色接口集合,一个实现类可实现多个
校验每个实现类没有被迫实现的无用方法
常见错误按实现类现有方法分组,而不是按调用方需求分组

典型使用场景

  • 报表与定时任务共用一个大接口:按角色拆成导出能力与调度能力两个接口
  • 设备管理:读取、配置、升级三类操作的使用方不同,拆开后无权限方不必依赖无关方法
  • 健康检查接口:只有探针需要,独立成角色后其他实现不必提供空方法
  • 文件处理的读与写:只读的使用方不应依赖写方法
  • 插件体系:宿主只依赖插件声明的角色,插件能力按需组合

从场景反推接口

从场景反推接口
# 先写场景,再定接口
场景 A:导出报表     → ReportExportable 的 export(Report)
场景 B:定时任务     → ScheduledRunnable 的 run()
场景 C:健康检查     → HealthProbeable 的 health()

# 实现类按需组合多个角色
class ReportJob implements ReportExportable, ScheduledRunnable

拆分判断对照

现象判断处理
实现类里出现抛异常的空方法接口过宽按调用方需求拆出角色接口
同一方法签名出现在多个接口命名与语义需统一保持名称一致并说明契约
调用方只用到一个方法存在依赖浪费单独抽出最小角色
接口只有一个实现且无扩展预期可能属于过度抽象先保留具体类型,出现第二个实现再抽接口
拆接口不等于拆类:一个类完全可以实现多个角色接口,内部逻辑保持不变。接口的作用是约束调用方能看见什么,而不是强制把实现也切碎。
接口数量会增加,命名要表达角色而非实现细节。按能力命名(可导出的、可调度的、可探活的)比按类型命名更容易在多个实现之间复用。

落地检查清单

  • 接口依据调用方场景定义,每个场景能说出用途
  • 实现类中没有被迫写出的空实现或抛异常实现
  • 调用方依赖的接口不包含它不会调用的方法
  • 新增场景时优先扩展角色,而不是加宽已有接口

易错点

  • 接口按实现类划分:调用方仍被迫依赖多余方法,隔离目标没有达成
  • 把接口拆到每个方法一个:角色语义消失,调用方需要组合多个接口才能表达一个用途
  • 相同签名分散在多个接口且命名不一致:同一实现在不同调用方看到的方法名不同,理解成本上升
  • 为每个类都抽一个接口:抽象层数量膨胀,除非存在替换或测试需求,否则不必抽

数据来源与参考

  • Robert C. Martin · ISP 论述与接口角色建模实践
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌