Go接口设计原则与SOLID原则
SOLID原则在Go接口设计中有独特实践方式。
SOLID原则概述
| 原则 | 全称 | Go实践 |
|---|---|---|
| S | 单一职责 | 小接口,方法少 |
| O | 开闭原则 | 接口扩展不改 |
| L | 里氏替换 | 实现满足语义 |
| I | 接口隔离 | 拆分大接口 |
| D | 依赖倒置 | 依赖接口 |
单一职责原则(SRP)
接口职责单一
Go
// 不推荐:接口职责混杂
type UserManager interface {
CreateUser()
DeleteUser()
SendEmail() // 邗件职责
LogAudit() // 日志职责
}
// 推荐:职责分离
type UserRepo interface {
Create()
Delete()
}
type EmailSender interface {
Send()
}
type AuditLogger interface {
Log()
}
一个接口只做一件事,方法不超过3个。
开闭原则(OCP)
扩展开放,修改关闭
Go
// 基础接口不变,通过组合扩展
type Reader interface {
Read(p []byte) (n int, err error)
}
// 扩展接口
type ReadCloser interface {
Reader
Closer
}
// 新增行为不影响原有接口
里氏替换原则(LSP)
实现必须满足接口语义
Go
type Writer interface {
Write(p []byte) (n int, err error)
}
// 实现必须保证:
// 1. 返回n表示写入字节数
// 2. err表示写入错误
// 3. 不能有违反语义的行为
type BadWriter struct{}
func (b BadWriter) Write(p []byte) (int, error) {
return 0, nil // 假装成功但没写入(违反语义)
}
type GoodWriter struct{}
func (g GoodWriter) Write(p []byte) (int, error) {
// 真实写入,语义正确
return len(p), nil
}
接口隔离原则(ISP)
拆分大接口
Go
// 不推荐:大接口,客户被迫依赖不需要的方法
type Worker interface {
Work()
Eat()
Sleep()
}
// 推荐:按需要拆分
type Doer interface {
Work()
}
type Eater interface {
Eat()
}
type Sleeper interface {
Sleep()
}
// 实现者只需实现需要的接口
type Robot struct{}
func (r Robot) Work() {}
// Robot不需要Eat和Sleep
依赖倒置原则(DIP)
依赖接口而非实现
Go
// 不推荐:依赖具体类型
type UserService struct {
repo *MySQLRepo // 依赖具体实现
}
// 推荐:依赖接口
type UserService struct {
repo UserRepo // 依赖接口
}
type UserRepo interface {
Find(id int) (*User, error)
Save(user *User) error
}
// 可替换实现
userService := UserService{repo: &PostgresRepo{}}
userService := UserService{repo: &MockRepo{}}
Go接口设计特点
隐式实现
Go
// Go接口隐式实现,无需显式声明
type Reader interface {
Read(p []byte) (n int, err error)
}
// 只要实现Read方法就满足Reader
type MyReader struct{}
func (m MyReader) Read(p []byte) (int, error) {
return len(p), nil
}
var r Reader = MyReader{} // 自动满足
接口在消费方定义
Go
// 接口由使用者定义,而非提供者
// 提供者提供具体类型
type File struct{}
func (f File) Read(p []byte) (int, error) { return 0, nil }
func (f File) Write(p []byte) (int, error) { return 0, nil }
// 使用者按需要定义接口
type MyReader interface {
Read(p []byte) (int, error) // 只需要Read
}
// File自动满足MyReader
设计原则实践表
| 原则 | Go实践 | 示例 |
|---|---|---|
| SRP | 接口方法≤3 | UserRepo只做用户操作 |
| OCP | 组合扩展 | Reader+Closer=ReadCloser |
| LSP | 语义一致 | Write返回真实写入量 |
| ISP | 按需拆分 | Doer/Eater/Sleeper分离 |
| DIP | 依赖接口 | Service依赖Repo接口 |
要点总结
- 单一职责:接口方法不超过3个
- 开闭原则:组合扩展不改原有接口
- 里氏替换:实现必须满足接口语义
- 接口隔离:拆分大接口,按需定义
- 依赖倒置:依赖接口而非具体类型
- Go接口隐式实现,无需声明
- 接口在消费方定义,更灵活
- SOLID原则指导高质量接口设计
📝 发现内容有误?点击此处直接编辑