前言
我们都知道OOP有两个方式,组合和继承来组织类,分别表示has-a关系和is-a关系,能够实现代码复用、提升扩展性和灵活性。
前面一篇讲方法method阐述了go通过结构体struct嵌套实现对象的扩展(相对于Java类的组合,has a关系),outer结构体会自动生成包装方法委托给inner嵌套结构的方法,这样实现了方法代码的复用。这样有了组合has-a关系,go里面的is-a关系是怎么实现的呢?下面我们来看看接口interface~
1.接口类型
类似于Java中的接口,接口类型描述了一系列方法的集合,一个实现了这些方法的具体类型是这个接口类型的实例。实现接口则不同于Java中需要显式地指明具体类implements实现了某个接口,go中的实现是隐式的,只要一个具体类型实现了某个接口的所有方法就足够了。
以我们最常用的fmt包的打印部分为例,Printf和Sprintf都包含格式化输出的部分,只是最终输出的目的地不一样,一个是标准输出还有一个是字符串,所以fmt包的实现将通用的格式化输出的部分抽取到Fprintf,然后将通用逻辑委托给它。Fprintf的前缀F表示文件(File),输出结果应该被写入第一个参数,第一个参数io.Writer是是用得最广泛的接口之一,因为它提供了所有类型的写入bytes的抽象,包括文件类型,内存缓冲区,网络链接等等。Reader则相反,代表任意可以读取bytes的类型。
func Printf(format string, args ...interface{}) (int, error) {
return Fprintf(os.Stdout, format, args...) // 通用逻辑
}
func Sprintf(format string, args ...interface{}) string {
var buf bytes.Buffer
Fprintf(&buf, format, args...) // 通用逻辑
return buf.String()
}
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {}
// 接口
type Writer interface {
Write(p []byte) (n int, err error)
}
type Stringer interface {
String() string
}
1.2 接口组合(嵌套)
新的接口类型通过组合已有的接口来定义,这样可以很简短地包括所有方法,也可以与声明方法混合