面试题答案
一键面试举例说明反模式
假设我们有一个电商系统,设计了一个非常宽泛的 Product
接口,它涵盖了各种不同类型产品(如书籍、电子产品、食品等)的所有可能操作:
type Product interface {
GetName() string
GetPrice() float64
GetAuthor() string // 只适用于书籍
GetBrand() string // 适用于电子产品等
GetExpiryDate() time.Time // 适用于食品
// 更多各种类型产品可能的方法
}
对于书籍产品实现者,需要实现 GetBrand
和 GetExpiryDate
等与书籍无关的方法;食品产品实现者需要实现 GetAuthor
等无关方法,这就导致实现者负担过重。
改进方式
- 拆分为更细粒度的接口:
- 对于书籍,可以定义
Book
接口:
type Book interface { GetName() string GetPrice() float64 GetAuthor() string }
- 对于电子产品,定义
ElectronicProduct
接口:
type ElectronicProduct interface { GetName() string GetPrice() float64 GetBrand() string }
- 对于食品,定义
Food
接口:
type Food interface { GetName() string GetPrice() float64 GetExpiryDate() time.Time }
- 对于书籍,可以定义
- 遵循接口隔离原则:让不同类型的产品实现各自对应的细粒度接口,而不是一个大而全的接口。这样每个实现者只需要关注自己真正需要实现的方法,降低了负担,也符合接口设计的最佳实践。例如:
type MyBook struct {
name string
price float64
author string
}
func (b MyBook) GetName() string {
return b.name
}
func (b MyBook) GetPrice() float64 {
return b.price
}
func (b MyBook) GetAuthor() string {
return b.author
}
这里 MyBook
结构体只实现 Book
接口的方法,而不需要处理其他无关方法。