Go接口应优先定义单方法、自解释命名的小接口,由消费者在调用处定义,避免膨胀与职责不清;组合小接口更安全,第三方类型可封装新接口;需定期检查僵尸接口与意外实现。

Go 接口隐式实现本身不增加维护负担,但会放大设计缺陷——接口膨胀、职责不清、契约模糊时,问题才真正浮现。
接口越小,越容易守住契约
隐式实现不检查“意图”,只校验方法签名。一个含 8 个方法的接口,只要漏实现 1 个,编译就报错;但若拆成 3 个单方法接口(如 Reader、Writer、Closer),每个实现都轻量明确,出错概率大幅降低,也更容易被单元测试覆盖。
- 优先定义单方法接口,按行为维度而非业务实体切分
- 组合小接口比堆砌大接口更安全:type ReadWriter interface{ Reader; Writer }
- 避免在接口里塞非核心行为(比如日志、通知),它们该由独立组件处理
接口必须在使用处定义
谁消费,谁定义。把 UserRepository 接口放在 dao 包里,等于让数据层决定上层怎么用它——这违背了“消费者驱动契约”的原则。正确做法是:业务逻辑层发现多个地方都需要查用户,再就地定义最小接口,然后注入具体实现。
- 接口文件应靠近调用方,而非实现方
- 第三方类型(如 time.Time)无法修改,但你能为它定义新接口并直接使用
- 重构时,先改调用代码里的接口定义,再调整实现,风险可控
命名即契约,文档即指南
隐式实现下,没人能从结构体声明看出它实现了哪些接口。所以接口名必须自解释:UserNotifier 比 Service 清晰,PaymentProcessor 比 Handler 可靠。同时,在接口上方加简短注释,说明“这个接口用于什么场景、不该做什么”。
立即学习“go语言免费学习笔记(深入)”;
- 避免泛化词:Handler、Manager、Service、Util
- 用动宾结构:SendEmail、ValidateInput、PersistRecord
- 必要时用 //go:generate mockgen 自动生成 mock,让依赖关系显性化
定期做接口健康检查
项目跑半年后,有些接口可能只剩 1 个实现,或方法中已有 2 个从未被调用。这类“僵尸接口”会拖慢理解成本。建议每季度快速扫描:
- 接口是否仍被两个及以上包引用?否则考虑内联或删除
- 每个方法是否在至少一处被真实调用?用 go tool trace 或 IDE 的“Find Usages”验证
- 实现类型是否意外满足了不该满足的接口?比如某个结构体恰好有 Close() 方法,却被当成 io.Closer 传入,引发资源误释放


















