您现在的位置是:首页 > 正文

interface使用

2024-02-01 01:01:37阅读 2

1interface接口

在GO语言中的interface,只需要记住以下三点:

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

 注意:

a:interface 可以被任意对象实现,一个类型/对象也可以实现多个interface。

b:方法不能重载,如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()
}

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

 

 

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()支付等。那么如果这个业务员模块只有这几个方法还好,但是随着我们的程序写的越来越复杂,银行业务员可能就要增加方法,会导致业务员模块越来越臃肿。

使用接口来统一规范:

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

}

4 面向对象中的依赖倒转原则

4.1 耦合度极高的模块关系设计

混乱的依赖关系.png

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接口层的代码,显然最后我们的两个业务 张三开奔驰, 李四开宝马,程序中也都实现了。但是这种设计的问题就在于,小规模没什么问题,但是一旦程序需要扩展,比如我现在要增加一个丰田汽车 或者 司机王五, 那么模块和模块的依赖关系将成指数级递增,想蜘蛛网一样越来越难维护和捋顺。

4.2 面向抽象层依赖倒转

 

                                                                               依赖倒转设计.png


如上图所示,如果我们在设计一个系统的时候,将模块分为3个层次,抽象层、实现层、业务逻辑层。那么,我们首先将抽象层的模块和接口定义出来,这里就需要了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)
}



 

网站文章

  • 数字字母下划线C语言,【判断题】C语言中的标识符只能由字母、数字和下划线三种字符组成,而且第一个字符只能是字母和下划线。...

    【判断题】C语言中的标识符只能由字母、数字和下划线三种字符组成,而且第一个字符只能是字母和下划线。更多相关问题计算机病毒按其寄生方式划分通常可分为()。A.系统引导型病毒B.文件型病毒C.在委托某工程...

    2024-02-01 01:01:10
  • 友元

    友元是一种定义在类外部的普通函数,但需要在类内进行声明,为了与该类的成员函数进行区分,在声明时加入关键字friend。它可以是一个函数,该函数称为友元函数。也可以是一个类,该类称为友元类。友元机制可以访问类中的保护成员和私有成员。 友元函数 class Point { private: double x,y; public: Point(double xx,double yy...

    2024-02-01 01:01:03
  • virtualhackinglabs靶机 Mon02 10.12.2.244

    virtualhackinglabs靶机 Mon02 10.12.2.244

    2024-02-01 01:00:55
  • MySQL索引背后的数据结构及算法原理

    MySQL索引背后的数据结构及算法原理

    摘要本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等。为了避免混乱,本文将只关注于BTree索引,因为这是平常使用MySQL时主要打交道的索引,至于哈希索引和全文索引本文暂不讨论。文章主要内容分为三个部分。第...

    2024-02-01 01:00:26
  • 获取当前日期是本年的第几周java与mysql获取值不一致

    SELECT YEARWEEK(now()); 在数据库查询出的本年第几周和java中获取的不一样, 研究了下原来是java里有两个关键设置,一个是从周几开始计算周,另外一个是一周最小要过了几天才算一...

    2024-02-01 01:00:17
  • RegExp对象的学习

    RegExp对象的学习

    1.科普:RegExp是js原生的内置对象,直接可以使用。e.g. :via RegExp.$1 取得第一个匹配子项;        默认带特殊含义的字符若要表达其本身就在其前面加个\转义,这些字符共...

    2024-02-01 01:00:11
  • js 遍历对象

    function allPrpos(obj) { // 用来保存所有的属性名称和值 var props = &quot;&quot;; // 开始遍历 for(var p in obj){ // 方法 if(typeof(obj[p])==&quot;function&quot;){ ...

    2024-02-01 00:59:43
  • 必须要学习的源码--ConcurrentHashMap

    必须要学习的源码--ConcurrentHashMap

    开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,

    2024-02-01 00:59:38
  • 并发编程学习一

    关键信息作为笔记记录一下。1、重要模型:信号量模型,管程模型。管程是解决并发问题的万能钥匙(暂时还不是特别理解)。2、并发编程可以总结为三个核心问题:分工、同步、互斥。(并发包的设计可从这三个角度去划...

    2024-02-01 00:59:33
  • 浅谈 Integer的自动拆箱和装箱

    浅谈 Integer的自动拆箱和装箱

    public class IntegerDemo { public static void main(String[] args) { Integer i1 = 128; Integer i2 = 128; System.out.println(i1 == i2); System.out.println(i1.equals(i2)); System.out.pri...

    2024-02-01 00:59:25