接口隔离的实操顺序
接口隔离原则常被表述为「不该强迫调用方依赖它不使用的方法」,实操时更有效的方式是从调用方反推接口:先列出每个使用场景真正需要的方法集合,把同类场景合并,得到一组角色接口。实现类按能力实现多个角色,调用方只依赖它需要的那个角色。判断做得好不好,看每个实现类是否还存在被迫写出的空方法或抛异常方法。
实操路径
| 起点 | 调用方需求清单,按使用场景逐条列出 |
|---|---|
| 产物 | 角色接口集合,一个实现类可实现多个 |
| 校验 | 每个实现类没有被迫实现的无用方法 |
| 常见错误 | 按实现类现有方法分组,而不是按调用方需求分组 |
典型使用场景
- 报表与定时任务共用一个大接口:按角色拆成导出能力与调度能力两个接口
- 设备管理:读取、配置、升级三类操作的使用方不同,拆开后无权限方不必依赖无关方法
- 健康检查接口:只有探针需要,独立成角色后其他实现不必提供空方法
- 文件处理的读与写:只读的使用方不应依赖写方法
- 插件体系:宿主只依赖插件声明的角色,插件能力按需组合
从场景反推接口
从场景反推接口
# 先写场景,再定接口
场景 A:导出报表 → ReportExportable 的 export(Report)
场景 B:定时任务 → ScheduledRunnable 的 run()
场景 C:健康检查 → HealthProbeable 的 health()
# 实现类按需组合多个角色
class ReportJob implements ReportExportable, ScheduledRunnable拆分判断对照
| 现象 | 判断 | 处理 |
|---|---|---|
| 实现类里出现抛异常的空方法 | 接口过宽 | 按调用方需求拆出角色接口 |
| 同一方法签名出现在多个接口 | 命名与语义需统一 | 保持名称一致并说明契约 |
| 调用方只用到一个方法 | 存在依赖浪费 | 单独抽出最小角色 |
| 接口只有一个实现且无扩展预期 | 可能属于过度抽象 | 先保留具体类型,出现第二个实现再抽接口 |
拆接口不等于拆类:一个类完全可以实现多个角色接口,内部逻辑保持不变。接口的作用是约束调用方能看见什么,而不是强制把实现也切碎。
接口数量会增加,命名要表达角色而非实现细节。按能力命名(可导出的、可调度的、可探活的)比按类型命名更容易在多个实现之间复用。
落地检查清单
- 接口依据调用方场景定义,每个场景能说出用途
- 实现类中没有被迫写出的空实现或抛异常实现
- 调用方依赖的接口不包含它不会调用的方法
- 新增场景时优先扩展角色,而不是加宽已有接口