Go 接口是隐式满足(duck typing),设计原则与 Java 差异很大:接口应该小,一至两个方法最理想(io.Reader、io.Writer 是典范);接口定义在消费方而不是实现方——谁依赖抽象谁定义接口,实现方只导出具体类型,这避免了 Java 式'每个类配一个接口'的冗余。
'接受接口、返回结构体'(Accept interfaces, return structs):函数参数用接口声明最小依赖,方便替换实现和 mock;返回值用具体类型,把是否抽象的决定权留给调用方,因为返回接口等于替调用方做了抽象承诺,后续想加方法或改实现都受束缚。
// 消费方定义自己需要的小接口
type UserStorer interface {
Get(ctx context.Context, id int64) (*User, error)
}
func NewService(s UserStorer) *Service { return &Service{store: s} }
易错点:过度抽象——只有一个实现时也先定义接口,增加间接成本;接口越大越难 mock;测试替身可直接用小接口手写 fake,不一定要上 mock 框架。追问方向:接口组合(io.ReadWriter)、编译期断言 var _ Iface = (*T)(nil) 的作用。