Golang 接口
接口( interface ),定义了( 一系列 )对象的行为规范( 只定义,不实现,由具体的对象来实现规范的细节 )
接口,就像是一种约定,概括了一种类型,应该具备哪些方法
这种设计,符合程序开发中,抽象的一般规律 // So,为什么使用接口 ? 面向对象编程 or 面向接口编程( 多态 )
- 实现方式:Java 中,也有接口的概念,不过,Java 中,需要显式的声明:一个类,实现了哪些接口,而,Golang 中,使用隐式声明的方式实现接口,即:只要一个类型实现了接口中规定的所有方法,那么,它就实现了这个接口
- 类型和接口的关系:多对多 & ( 接口 )组合
- 一个类型,可以实现多个接口 // 接口类型变量:接口,是一个自定义类型
- 不同的类型,还可以实现同一个接口 // 接口实现:值类型接收者 or 指针类型接收者
- 接口组合:接口与接口之间,可以通过互相嵌套,形成新的接口类型
- 拓展:空接口 - 接口值 & 类型断言
Golang 中,提倡使用面向接口编程的方式,实现解耦, // 具体的类型,更注重 "我是谁"
让我们专注于该类型提供的方法( "能做什么" ),而不是类型本身,从而写出更加通用和灵活的代码
接口的定义和实现
// 基本语法 type 接口类型名 interface{ 方法名1( 参数列表1 ) 返回值列表1 方法名2( 参数列表2 ) 返回值列表2 … }
// 接口,一种( 抽象 )的自定义类型 type Payer interface { // 接口变量的命名,一般以 er 结尾 // 接口类型,是一组方法的集合,它规定了需要实现的所有方法 Pay() // 方法声明,只定义规范,不实现 } // 对象:不同的支付方式 type ZfbPay struct{} type WxPay struct{} // ( 面向对象编程 - 定义对象的方法 )( 面向接口编程 - 实现支付接口 ) // 二者的区别在于:接口,更像是一种约定,规定了一个需要实现的方法列表,而,实现接口的方式就是:实现接口中规定的所有方法 func (z *ZfbPay) Pay() { fmt.Println("ZfbPay") } func (w *WxPay) Pay() { fmt.Println("WxPay") } func main() { var zfbPay ZfbPay var wxPay WxPay // 面向对象编程:对象.方法 zfbPay.Pay() // ZfbPay wxPay.Pay() // WxPay // 面向接口编程 - 接口类型变量 / 多态:父类引用指向子类对象( 值类型 or 指针类型,与方法接收者类型一致 ) // 方式1:接口类型变量:一个接口类型的变量,能够存储所有实现了该接口的类型变量 var pay Payer pay = &zfbPay pay.Pay() // ZfbPay pay = &wxPay pay.Pay() // WxPay // 方式2( 推荐 ):多态 CheckOut(&zfbPay) // ZfbPay CheckOut(&wxPay) // WxPay } // 多态的实现 - 函数形式 func CheckOut(payer Payer) { payer.Pay() }
「 接口组合 」接口与接口之间,可以通过互相嵌套,形成新的接口类型;
这种由多个接口类型组合形成的新接口类型,同样,只要实现新接口类型中规定的所有方法,就算实现了该接口类型
// Go标准库 io 源码中,就有很多接口之间互相组合的示例 type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type Closer interface { Close() error } // ReadWriter 是组合Reader接口和Writer接口形成的新接口类型 type ReadWriter interface { Reader Writer } // ReadCloser 是组合Reader接口和Closer接口形成的新接口类型 type ReadCloser interface { Reader Closer } // WriteCloser 是组合Writer接口和Closer接口形成的新接口类型 type WriteCloser interface { Writer Closer }