定义
客户端不应该被强迫依赖它不需要的接口,这里的客户端指接口的调用者
接口可以理解为下面三种东西:
一组API接口集合
单个API接口或者函数
OOP中的接口概念
一组API接口集合
一组API接口集合指的就是微服务或者类库
比如开发一个用户系统微服务,提供了一组和用户相关的接口给外部系统使用
type UserService interface {
Register(username string, password string)
Login(username string, password string)
GetUserInfoByID(id string)
}
此时后台管理系统有一个删除用户的需求,那么这个删除用户接口可以直接加在UserService中吗?
DeleteUser接口涉及用户删除,是一个安全性要求非常高的操作,只能由后台管理系统调用,其他系统不能调用,如果直接加在UserService中,UserService的其他调用方就也可以调用DeleteUser接口了
如果有接口鉴权框架,那么加在UserService中没有大问题,我们可以通过接口鉴权框架限制DeleteUser接口的调用方,防止UserService的其他调用方调用该接口
如果没有接口鉴权框架,我们就只能从代码层面限制DeleteUser接口的调用,将DeleteUser接口拆分到一个单独的RestrictedUserService中,只将RestrictedUserService暴露给后台管理系统,不暴露给其他系统,这样UserService的调用方就无法调用DeleteUser接口
微服务或者类库,如果它们中的某些API接口只被某些调用方使用的话,那么应该将这些API接口隔离出来,单独提供给那些调用方使用,而不是强迫其他调用方依赖这些用不到的接口
单个API接口或者函数
比如有一个统计信息的函数Count
type Statistics struct {
max int
min int
avg int
sum int
percentile99 int
percentile999 int
}
func (s *Statistics) Count(data []string) {
//根据data统计各种数据
}
这个Count函数就包含多个统计功能,统计最大值、最小值、平均值等等
如果使用到统计信息的地方,都是需要获取所有种类的统计数据那么Count函数可以认为职责单一;如果使用到统计信息的地方,都是只需要某一些种类的统计数据,比如只需要最大值、最小值等等,那么Count函数的职责就不单一,使用Count函数会增加一些多余的计算,降低性能,所以应该将Count函数拆成多个种类数据的单独统计函数,例如Max、Min、Avg等等
如果单个函数内部的某些功能只被部分调用者使用,那么应该将这些功能隔离出来,单独提供那些调用者
OOP中的接口
我们现在依赖Redis、Kafka、Mysql三个中间件,维护了三个中间件的Config,我们希望Redis、Kafka的配置具体热更新功能,Kafka、Mysql的配置具备可视化功能
type Updater interface {
Update(path string)
}
type Viewer interface {
OutputInPlainText()
}
type RedisConfig struct {
Address string
MaxCon int
MinCon int
}
func (c *RedisConfig) Update(path string) {
println("加载配置文件更新配置")
}
type KafkaConfig struct {
Address string
MaxCon int
MinCon int
}
func (c *KafkaConfig) Update(path string) {
println("加载配置文件更新配置")
}
func (c *KafkaConfig) OutputInPlainText() {
println("可视化展示配置")
}
type MysqlConfig struct {
Address string
MaxCon int
MinCon int
}
func (c *MysqlConfig) OutputInPlainText() {
println("可视化展示配置")
}
我们这里维护了两个单独的接口Updater、Viewer,需要热更新的Config实现Updater接口,需要可视化展示配置的Config实现Viewer接口,而不是采用一个大一统既包含热更新又包含可视化配置的Config接口
好处是:
- 接口的功能越单一,可复用性越强。比如我们又要开发一个Metrics性能统计模块,并且希望Metrics可以具备可视化展示功能,尽管Metrics和Config无关,也可以让Metrics实现Viewer接口即可
- 省去一些代码实现上的无用功。如果使用Config接口,RedisConfig不具备可视化配置功能还需要去实现OutputInPlainText方法,同理MysqlConfig不具备热更新功能还需要去实现Update方法;而且接口功能越单一,接口的实现类越少,接口变动时需要修改的类更少