Golang interface 介绍
interface 是 GO 语言的基础特性之一。可以理解为一种类型的规范或者约定。它跟 java,C# 不太一样,不需要显示说明实现了某个接口,它没有继承或子类或“implements”关键字,只是通过约定的形式,隐式的实现 interface 中的方法即可。因此,Golang 中的 interface 让编码更灵活、易扩展。
如何理解go 语言中的interface ? 只需记住以下三点即可:
- interface 是方法声明的集合
- 任何类型的对象实现了在 interface 接口中声明的全部方法,则表明该类型实现了该接口。
- interface 可以作为一种数据类型,实现了该接口的任何对象都可以给对应的接口类型变量赋值。
注意:
eat(), eat(s string)
package main
import "fmt"
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type ApplePhone struct {
}
func (iPhone ApplePhone) call() {
fmt.Println("I am Apple Phone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(ApplePhone)
phone.call()
}
interfacemain多态phone
面向对象 - 开闭原则
平铺式的模块设计
interface高内聚,低耦合开闭原则
package main
import "fmt"
//我们要写一个类,Banker银行业务员
type Banker struct {
}
//存款业务
func (this *Banker) Save() {
fmt.Println( "进行了 存款业务...")
}
//转账业务
func (this *Banker) Transfer() {
fmt.Println( "进行了 转账业务...")
}
//支付业务
func (this *Banker) Pay() {
fmt.Println( "进行了 支付业务...")
}
func main() {
banker := &Banker{}
banker.Save()
banker.Transfer()
banker.Pay()
}
Save()Transfer()Pay()
这样的设计会导致,当我们去给 Banker 添加新的业务的时候,会直接修改原有的 Banker 代码,那么 Banker 模块的功能会越来越多,出现问题的几率也就越来越大,假如此时 Banker 已经有 99 个业务了,现在我们要添加第 100 个业务,可能由于一次的不小心,导致之前 99 个业务也一起崩溃,因为所有的业务都在一个 Banker 类里,他们的耦合度太高,Banker 的职责也不够单一,代码的维护成本随着业务的复杂正比成倍增大。
开闭原则设计
interface支付Banker(实现支付方法)转账Banker(实现转账方法)
股票Banker(实现股票方法)
所以以上,当我们给一个系统添加一个功能的时候,不是通过修改代码,而是通过增添代码来完成,那么就是开闭原则的核心思想了。所以要想满足上面的要求,是一定需要 interface 来提供一层抽象的接口的。
golang 代码实现如下:
package main
import "fmt"
//抽象的银行业务员
type AbstractBanker interface{
DoBusi() //抽象的处理业务接口
}
//存款的业务员
type SaveBanker struct {
//AbstractBanker
}
func (sb *SaveBanker) DoBusi() {
fmt.Println("进行了存款")
}
//转账的业务员
type TransferBanker struct {
//AbstractBanker
}
func (tb *TransferBanker) DoBusi() {
fmt.Println("进行了转账")
}
//支付的业务员
type PayBanker struct {
//AbstractBanker
}
func (pb *PayBanker) DoBusi() {
fmt.Println("进行了支付")
}
func main() {
//进行存款
sb := &SaveBanker{}
sb.DoBusi()
//进行转账
tb := &TransferBanker{}
tb.DoBusi()
//进行支付
pb := &PayBanker{}
pb.DoBusi()
}
AbstractBanker
//实现架构层(基于抽象层进行业务封装-针对interface接口进行封装)
func BankerBusiness(banker AbstractBanker) {
//通过接口来向下调用,(多态现象)
banker.DoBusi()
}
那么 main 中可以如下实现业务调用:
func main() {
//进行存款
BankerBusiness(&SaveBanker{})
//进行存款
BankerBusiness(&TransferBanker{})
//进行存款
BankerBusiness(&PayBanker{})
}
再看开闭原则定义:
开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
简单的说就是在修改需求的时候,应该尽量通过扩展来实现变化,而不是通过修改已有代码来实现变化。
interface 的意义
调用未来
面向对象中的依赖倒转原则
耦合度高的设计举例
实现代码如下:
package main
import "fmt"
// === > 奔驰汽车 <===
type Benz struct {
}
func (this *Benz) Run() {
fmt.Println("Benz is running...")
}
// === > 宝马汽车 <===
type BMW struct {
}
func (this *BMW) Run() {
fmt.Println("BMW is running ...")
}
//===> 司机张三 <===
type Zhang3 struct {
//...
}
func (zhang3 *Zhang3) DriveBenZ(benz *Benz) {
fmt.Println("zhang3 Drive Benz")
benz.Run()
}
func (zhang3 *Zhang3) DriveBMW(bmw *BMW) {
fmt.Println("zhang3 drive BMW")
bmw.Run()
}
//===> 司机李四 <===
type Li4 struct {
//...
}
func (li4 *Li4) DriveBenZ(benz *Benz) {
fmt.Println("li4 Drive Benz")
benz.Run()
}
func (li4 *Li4) DriveBMW(bmw *BMW) {
fmt.Println("li4 drive BMW")
bmw.Run()
}
func main() {
//业务1 张3开奔驰
benz := &Benz{}
zhang3 := &Zhang3{}
zhang3.DriveBenZ(benz)
//业务2 李四开宝马
bmw := &BMW{}
li4 := &Li4{}
li4.DriveBMW(bmw)
}
interface张三开奔驰李四开宝马丰田汽车王五
耦合度低的面向抽象编程设计
interface
我们在指定业务逻辑也是一样,只需要参考抽象层的接口来业务就好了,抽象层暴露出来的接口就是我们业务层可以使用的方法,然后可以通过多态的线下,接口指针指向哪个实现模块,调用了就是具体的实现方法,这样我们业务逻辑层也是依赖抽象成编程。
依赖倒转原则
来一起看一下修改的代码:
package main
import "fmt"
// ===== > 抽象层 < ========
type Car interface {
Run()
}
type Driver interface {
Drive(car Car)
}
// ===== > 实现层 < ========
type BenZ struct {
//...
}
func (benz * BenZ) Run() {
fmt.Println("Benz is running...")
}
type Bmw struct {
//...
}
func (bmw * Bmw) Run() {
fmt.Println("Bmw is running...")
}
type Zhang_3 struct {
//...
}
func (zhang3 *Zhang_3) Drive(car Car) {
fmt.Println("Zhang3 drive car")
car.Run()
}
type Li_4 struct {
//...
}
func (li4 *Li_4) Drive(car Car) {
fmt.Println("li4 drive car")
car.Run()
}
// ===== > 业务逻辑层 < ========
func main() {
//张3 开 宝马
var bmw Car
bmw = &Bmw{}
var zhang3 Driver
zhang3 = &Zhang_3{}
zhang3.Drive(bmw)
//李4 开 奔驰
var benz Car
benz = &BenZ{}
var li4 Driver
li4 = &Li_4{}
li4.Drive(benz)
}
举一反三 - 练习题
模拟组装2台电脑:
— 抽象层: 有显卡Card 方法display,有内存Memory 方法storage,有处理器CPU 方法calculate;
— 实现层层: 有 Intel因特尔公司 、产品有(显卡、内存、CPU),有 Kingston 公司, 产品有(内存3),有 NVIDIA 公司, 产品有(显卡);
— 逻辑层: 1.组装一台Intel系列的电脑,并运行,2.组装一台 Intel CPU Kingston内存 NVIDIA显卡的电脑,并运行。
golang 代码实现如下:
/*
模拟组装2台电脑
--- 抽象层 ---
有显卡Card 方法display
有内存Memory 方法storage
有处理器CPU 方法calculate
--- 实现层层 ---
有 Intel因特尔公司 、产品有(显卡、内存、CPU)
有 Kingston 公司, 产品有(内存3)
有 NVIDIA 公司, 产品有(显卡)
--- 逻辑层 ---
1. 组装一台Intel系列的电脑,并运行
2. 组装一台 Intel CPU Kingston内存 NVIDIA显卡的电脑,并运行
*/
package main
import "fmt"
//------ 抽象层 -----
type Card interface{
Display()
}
type Memory interface {
Storage()
}
type CPU interface {
Calculate()
}
type Computer struct {
cpu CPU
mem Memory
card Card
}
func NewComputer(cpu CPU, mem Memory, card Card) *Computer{
return &Computer{
cpu:cpu,
mem:mem,
card:card,
}
}
func (this *Computer) DoWork() {
this.cpu.Calculate()
this.mem.Storage()
this.card.Display()
}
//------ 实现层 -----
//intel
type IntelCPU struct {
CPU
}
func (this *IntelCPU) Calculate() {
fmt.Println("Intel CPU 开始计算了...")
}
type IntelMemory struct {
Memory
}
func (this *IntelMemory) Storage() {
fmt.Println("Intel Memory 开始存储了...")
}
type IntelCard struct {
Card
}
func (this *IntelCard) Display() {
fmt.Println("Intel Card 开始显示了...")
}
//kingston
type KingstonMemory struct {
Memory
}
func (this *KingstonMemory) Storage() {
fmt.Println("Kingston memory storage...")
}
//nvidia
type NvidiaCard struct {
Card
}
func (this *NvidiaCard) Display() {
fmt.Println("Nvidia card display...")
}
//------ 业务逻辑层 -----
func main() {
//intel系列的电脑
com1 := NewComputer(&IntelCPU{}, &IntelMemory{}, &IntelCard{})
com1.DoWork()
//杂牌子
com2 := NewComputer(&IntelCPU{}, &KingstonMemory{}, &NvidiaCard{})
com2.DoWork()
}
小结
以上是用面向对象的思维来理解 Golang 中的 interface,通过设计原则来正反举例该如何正确使用 interface(接口),从而做到“高内聚、低耦合”,让代码写起来更优雅、扩展性更好。