当前位置: 技术文章>> Golang修炼指南-面向对象的编程思维理解interface

文章标题:Golang修炼指南-面向对象的编程思维理解interface
  • 文章分类: 后端
  • 18643 阅读

一、 interface接口

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

  如何理解go 语言中的interface ? 只需记住以下三点即可:
  1. interface 是方法声明的集合

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

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

注意:
  a. interface 可以被任意对象实现,一个类型/对象也可以实现多个 interface
  b. 方法不能重载,如 eat(), eat(s string) 不能同时存在

package mainimport "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()}

上述中体现了interface接口的语法,在main函数中,也体现了多态的特性。
同样一个phone的抽象接口,分别指向不同的实体对象,调用的call()方法,打印的效果不同,那么就是体现出了多态的特性。

二、 面向对象中的开闭原则

2.1 平铺式的模块设计

那么作为interface数据类型,他存在的意义在哪呢? 实际上是为了满足一些面向对象的编程思想。我们知道,软件设计的最高目标就是高内聚,低耦合。那么其中有一个设计原则叫开闭原则。什么是开闭原则呢,接下来我们看一个例子:

package mainimport "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的职责也不够单一,代码的维护成本随着业务的复杂正比成倍增大。

2.2 开闭原则设计

那么,如果我们拥有接口, interface这个东西,那么我们就可以抽象一层出来,制作一个抽象的Banker模块,然后提供一个抽象的方法。 分别根据这个抽象模块,去实现支付Banker(实现支付方法),转账Banker(实现转账方法)

那么依然可以搞定程序的需求。 然后,当我们想要给Banker添加额外功能的时候,之前我们是直接修改Banker的内容,现在我们可以单独定义一个股票Banker(实现股票方法),到这个系统中。 而且股票Banker的实现成功或者失败都不会影响之前的稳定系统,他很单一,而且独立。

所以以上,当我们给一个系统添加一个功能的时候,不是通过修改代码,而是通过增添代码来完成,那么就是开闭原则的核心思想了。所以要想满足上面的要求,是一定需要interface来提供一层抽象的接口的。

golang代码实现如下:

package mainimport "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已经基本了解,那么接口的意义最终在哪里呢,想必现在你已经有了一个初步的认知,实际上接口的最大的意义就是实现多态的思想,就是我们可以根据interface类型来设计API接口,那么这种API接口的适应能力不仅能适应当下所实现的全部模块,也适应未来实现的模块来进行调用。 调用未来可能就是接口的最大意义所在吧,这也是为什么架构师那么值钱,因为良好的架构师是可以针对interface设计一套框架,在未来许多年却依然适用。


推荐文章