Go Interface Go的面向对象思想

inteface接口 

interface 是GO语言的基础特性之一。可以理解为一种类型的规范或者约定。它跟java,C# 不太一样,不需要显示说明实现了某个接口,它没有继承或子类或“implements”关键字,只是通过约定的形式,隐式的实现interface 中的方法即可。因此,Golang 中的 interface 让编码更灵活、易扩展。

如何理解go 语言中的interface ?只需记住以下三点即可。

 

1、interface是方法声明的集合

2、任何类型的对象实现了在interface接口中声明的全部方法,则表明该类型实现了接口。

3、interface可以作为一种数据类型,实现了该接口的任何对象都可以给对应的接口类型变量赋值。

 

interface 与 对象的 对应关系:interface可以被任意对象实现,一个类型/对象也可以实现多个interface.

Interface(接口)的意义:

实际上接口的最大的意义就是实现多态的思想, 就是我们可以根据interface类型来设计API接口,那么这种API接口的适应能力不仅能适应当下所实现的全部模块,也适应未来实现的模块来进行调用。 调用未来可能就是接口的最大意义所在吧,这也是为什么架构师那么值钱,因为良好的架构师是可以针对interface设计一套框架,在未来许多年却依然适用。

Interface  ,在 封装,实现(implements: 其他语言叫继承),多态。

例子 

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()
}
/**
多个对象 实现 接口,也体现了 多态 特性,同样的一个接口类型 变量 ,分别被赋予(指向)不同的实体对象,调用call()方法,执行的结果不同,
这就体现出了 多态的特性。  也可以说 体现了 封装(struct来体现) ,实现(implements), 多态

 */

面向对象中的依赖倒转原则 : 一句话 业务逻辑层 ,实现层 要依赖 抽象,而不是依赖细节!。

一些原则 是 从战略上 对业务进行抽象。

如何 对业务进行抽象出 一些 接口 (php语言中可以是 接口或抽象类)呢?来看一个例子:

业务层, 抽象层,实现层 。这个封层思想/方法 很好。一般程序员 可能是 业务层(需求)来了,想着 快速的实现(实现层),没有仔细地思考抽象层);更好的方式是 :业务层(需求) ,再抽象层,再实现层,再业务层。这个思考方式可以一开始就这样做,或者放在后面代码优化的时候再这样做。(因为并不是所有的需求都能很好的去抽象出来一些公共的东西,要看具体的业务是什么)

 

从 张三开奔驰,李四开宝马 到 司机开车的抽象(抽象层); 张三,李四 实现司机;奔驰,宝马实现车; 最后实现 张三开奔驰,李四开宝马的业务需求(业务逻辑层)

代码如下:

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显卡的电脑,并运行

代码如下:

package main
import "fmt"

//------  抽象层 -----
type Card interface{
	Display()
}

type Memory interface {
	Storage()

	/**
	模拟了一种情景,接口层写好了,实现层写好了,业务层写好了。代码完美运行了一段时间。某天某个人对接口层加上了一个方法!
	这时可能会出现什么情况呢?
	1. 程序报错了,报类型不对的错误! 原因是 子类(实现层的struct /对象)没有实现这个方法,接口与这个 struct对象(php类比子类)无任何关系了。
	2。程序依然正常的运行着。 为什么呢?很可能是 struct对象 显示地 继承接口 的写法。
	总结 看来显示地 实现接口,也是有着一定好处的!同样也可能意味着接口着很多或更多的功能(方法)你子类(struct对象)并没有使用(实现)!!
	本人目前觉得 显式地 继承/实现 好一些,坏处有哪些?尚不清楚!
	与PHP implements/extends 比较 Go 的interface  似乎更加灵活,像php子类不实现接口中的所有方法就会报错!!,而Go不会!
	显示地 实现接口还有一个好处,就是我不用编辑器提示,我就知道这个struct 实现了该接口!这对大型工程,或者不使用编辑提示功能情况下,显得尤其
	方便和重要!
	 */
	Card
}

type CPU interface {
	Calculate()
}

type Computer struct {
	cpu CPU
	mem Memory
	card Card
}


func (computer *Computer) DoWork() {
	computer.cpu.Calculate()
	computer.mem.Storage()
	computer.card.Display()
}

func NewComputer(cpu CPU, mem Memory, card Card) *Computer{
	return &Computer{
		cpu:cpu,
		mem:mem,
		card:card,
	}
}

//------  实现层 -----
//intel
type IntelCPU struct {
	//CPU                //这里你可能有疑问,只要实现Calculate() 方法就可以被认为是 CPU 了,然而写了也没错,因为抽象层和实现层都是你一个人
					//写的,你很清楚你写的IntelCPU 就是一款CPU ,相当于其他语言如PHP 显式地 extends 或 implements
}

func (this *IntelCPU) Calculate() {
	fmt.Println("Intel CPU 开始计算了...")
}

type IntelMemory struct {
	Memory  //这里你可能有疑问,只要实现Storage() 方法就可以被认为是 Memory 了,然而写了也没错,因为抽象层和实现层都是你一个人
	//写的,你很清楚你写的IntelMemory 就是一款Memory ,相当于其他语言如PHP 显式地 extends 或 implements; 这样还有一个好处就是不管以后接口(抽象层)
	//又增加了一个方法(你不知道,抽象层也没有义务非要告诉你),这时候显式好处是 程序依然认为你的 实现层IntelMemory 依然实现了Memory接口。
	//尽管你并没有实现它(interface接口)的新增的那个方法!
}

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()
}

 

总结 看来显示地 实现接口,也是有着一定好处的!
1.这样还有一个好处就是不管以后接口(抽象层)又增加了一个方法(你不知道,抽象层也没有义务非要告诉你),这时候显式好处是 程序依然认为你的 实现层IntelMemory 依然实现了Memory接口。尽管你并没有实现它(interface接口)的新增的那个方法!  同样也可能意味着接口着很多或更多的功能(方法)你子类(struct对象)并没有使用(实现)!!

2.显示地 实现接口还有一个好处,就是我不用编辑器提示,我就知道这个struct 实现了该接口!这对大型工程,或者不使用编辑提示功能情况下,显得尤其 方便和重要!

Go 是面向对象的编程语言吗?

官方FAQ给出了标准答案: Yes  and No.

还有一种“模拟”产生子类的方法,就是通过在类型中嵌入其它的类型,但是这是一种“组合”的方式,而不是继承。

嵌入深度。如果没有嵌入,我们定义嵌入深度为0,如果有嵌入,并且嵌入的接口没有嵌入的话,我们称之为深度为1,以此类推。比如下面接口A的嵌入深度为2:

type A interface {
B // 嵌入
}

type B interface {
C
}
type C interface {
}

【标准库中接口中嵌入接口的数量】:  绝大部分的接口(131 个)都不会嵌入其它接口的,嵌入最多的是mime/multipart.File[2],嵌入了四个接口:

其它 6 个项目(Docker、etcd、grpc-go、prometheus、consul、influxdb )使用接口的情况:可以看到同样大部分接口嵌入数量都在 0 个或者 1 个,嵌入最多的是 kubernetes 的CoreV1Interface[3]接口,嵌入了 16 个接口,可以说是一个巨无霸嵌入接口了:

【嵌入的接口深度】:准库中不使用太深的嵌入方式,比较多的也就是嵌入一次。

精选项目中使用接口的方式也一样,很少使用嵌入深度很长的方式,最长也就是 2,而且只有两个接口:kubernetes/.../Stream[4]和moby/.../WriteCommitCloser[5],而且主要是因为嵌入io.ReadWriteCloserio.WriteCloser导致。

【接口中直接定义的方法的数量】:

准库中接口定义的直接方法的数量都很少,不会设置很多的方法,接口都比较精巧干练(7个以内),比较特殊的是reflect/Type[6]接口,定义了 31 个直接方法。 

同样,精选项目中的接口直接定义的方法也比较少,超过 10 个方法的接口少之又少,最多的是influxdata/.../TSMFile[7]接口,定义了足足 42 个方法。

【接口中总的方法的数量】:

标准库中 1 接口的总方法数量基本都在 8 个以下。

精选项目中接口定义的总方法基本都在 12 个以下。

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值