• 【无标题】


    Go中interface编程思想

    理解interface

    • interface是方法声明的集合
    • 任何类型的对象实现了interface接口中声明的全部方法,则表明该类型实现了接口
    • interface可以作为一种数据类型,实现该接口的任何对象都可以对对应接口类型变量赋值。

    开闭原则

    interface的意义其实是为了满足软件设计的高内聚、低耦合思想。那这其中就需要满意一些原则,如:开闭原则
    举例:

    package main
    
    import "fmt"
    
    type Banker struct {
    }
    
    // Save 存款业务
    func (this *Banker) Save() {
    	fmt.Println("进行了 存款业务...")
    }
    
    // Transfer 转账业务
    func (this *Banker) Transfer() {
    	fmt.Println("进行了 转账业务...")
    }
    
    // Pay 支付业务
    func (this *Banker) Pay() {
    	fmt.Println("进行了 支付业务...")
    }
    
    func main() {
    	banker := &Banker{}
    
    	banker.Save()
    	banker.Pay()
    	banker.Transfer()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    上面的例子很简单,银行业务有:存款业务、转账业务、支付业务。但是后面会增加很多很多业务的时候,这里业务模块会爆炸。
    每次新增业务都要这里添加业务,如果新加的业务崩溃也会导致前面业务一起挂掉。业务都在一个Banker中,耦合度太高,开发人员维护成本太高。

    如何优化?
    我们可以使用interface将业务抽象出来,制作一个抽象的Banker模块,然后提供一个抽象的方法。 分别根据这个抽象模块,
    去实现支付Banker(实现支付方法),转账Banker(实现转账方法)。
    当我们给一个系统添加一个功能的时候,不是通过修改代码,而是通过增添代码来完成,那么就是开闭原则的核心思想了。所以要想满足上面的要求,
    是一定需要interface来提供一层抽象的接口的。
    代码修改如下:

    
    func main() {
    	/*	banker := &Banker{}
    
    		banker.Save()
    		banker.Pay()
    		banker.Transfer()*/
    
    	/*//进行存款
    	sb := &SaveBanker{}
    	sb.DoBusiness()
    
    	//进行转账
    	tb := &TransferBanker{}
    	tb.DoBusiness()
    
    	//进行支付
    	pb := &PayBanker{}
    	pb.DoBusiness()
    	*/
    	// 存款
    	BankerBusiness(&SaveBanker{})
    
    	// 转账
    	BankerBusiness(&TransferBanker{})
    
    	// 支付
    	BankerBusiness(&PayBanker{})
    }
    
    // AbstractBanker 抽象银行业务
    type AbstractBanker interface {
    	DoBusiness()
    }
    
    // TransferBanker 转账业务员 进行转账业务
    type TransferBanker struct {
    }
    
    func (tb *TransferBanker) DoBusiness() {
    	fmt.Println("用户转账...")
    }
    
    // SaveBanker 存库业务员 进行存库业务
    type SaveBanker struct {
    }
    
    func (sb *SaveBanker) DoBusiness() {
    	fmt.Println("用户存款...")
    }
    
    // PayBanker 支付的业务员
    type PayBanker struct {
    	//AbstractBanker
    }
    
    func (pb *PayBanker) DoBusiness() {
    	fmt.Println("进行支付")
    }
    
    // BankerBusiness 实现架构层(基于抽象层进行业务封装-针对interface接口进行封装)
    func BankerBusiness(banker AbstractBanker) {
    	//通过接口来向下调用,(多态现象)
    	banker.DoBusiness()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    依赖倒置

    在软件设计的时候,一般为了业务功能扩展性会将模块分为3个层次,抽象层、实现层、业务逻辑层。
    如何做?
    先将抽象层的模块和接口定义出来, 这里就需要interface接口的设计,然后我们依照抽象层,依次实现每个实现层的模块,在我们写实现层代码的时候,实际上我们
    只需要参考对应的抽象层实现就好了,实现每个模块,也和其他的实现的模块没有关系,这样也符合了上面介绍的开闭原则。这样实
    现起来每个模块只依赖对象的接口,而和其他模块没关系,依赖关系单一。
    指定业务逻辑也是一样,只需要参考抽象层的接口来业务就好了,抽象层暴露出来的接口就是我们业务层可以使用的方法,然后
    可以通过多态的线下,接口指针指向哪个实现模块,调用了就是具体的实现方法,这样我们业务逻辑层也是依赖抽象成编程。
    这种的设计原则就叫做依赖倒转原则。
    示例:
    组装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
    	card   Card
    	memory Memory
    }
    
    func NewComputer(cpu CPU, card Card, memory Memory) *Computer {
    	return &Computer{
    		cpu:    cpu,
    		card:   card,
    		memory: memory,
    	}
    }
    
    func (c *Computer) DoWork() {
    	c.cpu.Calculate()
    	c.card.Display()
    	c.memory.Storage()
    }
    
    // 实现层
    type IntelCard struct {
    	Card
    }
    
    func (intel *IntelCard) Display() {
    	fmt.Println("intel card 显示内容了。。。")
    }
    
    type IntelMemory struct {
    	Memory
    }
    
    func (intel *IntelMemory) Storage() {
    	fmt.Println("intel memory storage ...")
    }
    
    type IntelCpu struct {
    	CPU
    }
    
    func (intel *IntelCpu) Calculate() {
    	fmt.Println("intel calculate 计算内容...")
    }
    
    type KingstonMemory struct {
    	Memory
    }
    
    func (k *KingstonMemory) Storage() {
    	fmt.Println("Kingston's memory (内存3) storage ...")
    }
    
    type NVIDIACard struct {
    	Card
    }
    
    func (n *NVIDIACard) Display() {
    	fmt.Println("NVIDIA card 显示内容了。。。")
    }
    
    // 逻辑层
    func main() {
    	//intel系列的电脑
    	com1 := NewComputer(&IntelCpu{}, &IntelCard{}, &IntelMemory{})
    	com1.DoWork()
    	// 其他牌子
    	com2 := NewComputer(&IntelCpu{}, &NVIDIACard{}, &KingstonMemory{})
    	com2.DoWork()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    参考

    • https://www.yuque.com/aceld/golang/uh0124
  • 相关阅读:
    前端笔试题总结,带答案和解析(三)
    卷积神经网络——vgg16网络及其python实现
    Matlab/Python教程系列 | 根据目录下的已有图片制作视频(动画)
    db2中kettle报错 Field [XXX] is required and couldn‘t be found 解决方法
    18 | 注解和反射
    Unity3D C# 反射与特性的配合使用
    QT6找不到QRegExpValidator类问题解决办法
    【Linux】(小白向)详解VirtualBox网络配置-配置Linux网络
    一文带你了解人工智能:现状、应用、变革及未来展望
    Cesium加载离线地图和离线地形
  • 原文地址:https://blog.csdn.net/u014753629/article/details/126876025