上一篇青训营文章聊到了Go语言中的接口,从Go运行时谈到了接口的nil误区,这次来聊一聊Go中接口具体的使用。
在使用接口之前,要知道一条前置原则:在实际真正需要的时候才对程序进行抽象。也就是 不要为了抽象而抽象。
比如,假如只就实现一个简单的加法函数,就没必要再去定义一个接口,再去实现。
type Adder interface {
Add(a ,b int) int
}
func Add(adder Adder,a,b int) int {
return adder.Add(a,b)
}
如上面的代码,这样会造成代码冗余,过度设计。接口虽然可以实现 解耦,但它也会引起额外副作用,会造成运行效率的下降,也会影响代码的可读性。
Go语言中的组合设计哲学
Go语言之父Rob Pike曾说过: 如果C++和Java是关于类型层次结构和类型分类的语言,那么Go则是关于组合的语言。接口作为Go语言提供的具有天然正交性的语法元素,在Go程序的静态结构搭建与耦合设计中扮演着至关重要的角色,主要有两种组合方式。
垂直组合
Go语言通过类型嵌入实现垂直组合
通过嵌入接口构建接口
通过在接口定义中嵌入其他接口类型,实现接口行为聚合,组成大接口
如ReadWriter接口类型:
type ReadWriter interface {
Reader
Writer
}
通过嵌入接口构建结构体类型
type MyReader struct {
io.Reader // underlying reader
N int64 // max bytes remaining
}
通过嵌入结构体类型构建新结构体类型
在结构体中嵌入接口类型名和在结构体中嵌入其他结构体
水平组合
当我们通过垂直组合将一个个类型建立完毕后,应用骨架就已经搭建好了,接下来就需要一个连接骨架的关节,把骨架拼成一个完整可运行的应用。接口可以将各个类型水平组合连接在一起。通过接口,整个应用程序不再是一个个孤立的一部分,而是一幅完整的、有灵活性和扩展性的静态骨架结构。
接口的几种应用模式
基本模式
接受接口类型参数的函数或方法是水平组合的基本语法
func func(param IfaceType)
函数参数中的接口类型作为“关节”,支持将位于多个包中的多个类型与func函数连接到一起,共同实现函数功能。接口类型和它的实现者之间还满足了:依赖抽象、里氏替换原则、接口隔离等代码设计原则。
创建模式
type Cond struct {
... ...
L Locker
}
func NewCond(l Locker) *Cond {
return &Cond{L: l}
}
在这里,sync标准库cond。通过接收Locker接口,返回Cond接口体,实现创建一个Cond实例。大多数包含接口类型字段的结构体的实例化,都可以使用创建模式实现。
包装器模式
在基本模式的基础上,当返回值的类型与参数类型相同时,就是包装器模式,如标准库io库里的使用:
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
}
func (l *LimitedReader) Read(p []byte) (n int, err error) {
// ... ...
}
适配器模式
适配器函数类型是一个辅助水平组合实现的“工具”类型, 它是一个类型,它可以将一个满足特定函数签名的普通函数,显式转换成自身类型的实例,转换后的实例同时也是某个接口类型的实现者。
如http库里的HandlerFunc:
func greeting(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
func main() {
http.ListenAndServe(":8080", http.HandlerFunc(greeting))
}
// HandlerFunc适配器
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
这里通过http.HandlerFunc这个适配器函数类型,将普通函数greeting快速转化为满足http.Handler接口的类型。
中间件
中间件就是包装模式和适配器模式结合的产物。
小结
主要介绍了接口的前置原则,两种组合以及几种模式。