[go学习笔记.第十章.面向对象编程] 10.面向对象的特性-接口

1.基本介绍

接口( interface ) ,在 Golang 中多态特性主要是通过接口来体现的

2.快速入门

package main

import(
    "fmt"
)

// 声明一个接口
type Usb interface {
    //声明了两个没有实现的方法
    Start()
    Stop()
}

//声明一个结构体,实现Usb方法
type Phone struct{

}

func (p Phone) Start()  {
    fmt.Println("手机开始工作...")
}
func (p Phone) Stop()  {
    fmt.Println("手机停止工作...")
}

//相机实现Usb方法
type Camera struct{

}

func (c Camera) Start()  {
    fmt.Println("相机开始工作...")
}
func (c Camera) Stop()  {
    fmt.Println("相机停止工作...")
}

//计算机
type Computer struct{

}
//编写一个方法Working, 接收一个Usb接口类型变量
//实现了Usb接口(就是指实现了Usb接口声明的所有方法)
func (c Computer) Working(usb Usb)  {
    //通过Usb接口变量来调用Start,Stop方法
    usb.Start()
    usb.Stop()
}

func main()  {
    //先创建结构体变量
    computer := Computer{}
    phone := Phone{}
    camera := Camera{}

    //关键点
    computer.Working(phone)
    computer.Working(camera)
}
手机开始工作...
手机停止工作...
相机开始工作...
相机停止工作...

接口概念的再说明

interface 类型可以定义一组方法,但是这些不需要实现,并且 interfaoe 不能包含任何变量,到某个自定义类型(比如结构体 Phone )要使用的时候,再根据具体情况把这些方法写出来(实现)

3.基本语法

type 接口名 interface {

        method1(参数列表) 返回值列表

        method2(参数列表) 返回值列表

实现接口的方法:

function (t 自定义类型) method1(参数列表) 返回值列表{

        //方法实现

}

function (t 自定义类型) method2(参数列表) 返回值列表{

        //方法实现

}

小节说明

(1).接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态高内聚低偶合的思想

(2 ). go中的接口,不需要显式的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此, Golang 中没有implement 这样的关键字

应用场景

4.接口的注意事项和细节

(1).接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)

package main

import(
    "fmt"
)

type AInterface interface{
    Say()
}

type Student struct{
    Name string
}
func (stu Student) Say(){
    fmt.Println("Stu Say()")
}

func main()  {
    var stu Student //结构体变量,实现了Say(),也就实现了AInterface接口
    var a AInterface = stu
    a.Say()
}

(2).接口中的所有的方法都没有方法体,即都没有实现的方法

(3).在go中,一个自定义类型需要将某个接口的所有方法都实现,才会说这个自定义类型实现了该接口

(4).一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型

(5 ).只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型

package main

import(
    "fmt"
)
type integer int
func (i integer) Say()  {
    fmt.Println("i integer, i=", i)
}
func main()  {
    var i integer = 10
    var b AInterface = i
    b.Say()//i integer, i= 10
}

(6).一个自定义类型可以实现多个接口

package main

import(
    "fmt"
)

type AInterface interface{
    Say()
}
type BInterface interface{
    Hello()
}

type Monster struct{

}
func (m Monster) Say() {
    fmt.Println("Monster Say()")
}
func (m Monster) Hello() {
    fmt.Println("Monster Hello()")
}
func main()  {
    //Monster实现了AInterface,BInterface
    var monster Monster
    var a1 AInterface = monster
    var b1 BInterface = monster
    a1.Say()
    b1.Hello()
}

(7).go接口不能有任何变量

(8).一个接口(比如A接口 )可以继承多个别的接口(比如 B , C 接口),这时如果要实现A接口,也必须将 B ,C 接口的方法也全部实现

package main

import(
    "fmt"
)

type BInterface interface{
    test01()
}
type CInterface interface{
    test02()
}
type AInterface interface{
    BInterface
    CInterface
    test03()
}

//如果需要实现AInterface,就需要把BInterface,CInterface额方法都实现
type Stu struct{

}
func (stu Stu) test01() {
    
}
func (stu Stu) test02() {
    
}
func (stu Stu) test03() {
    
}

func main()  {
    var stu Stu
    var a AInterface = stu
    a.test01()
}

(9).interface 类型默认是一个指针,如果没有对interface 初始化就使用,那么会输出nil

(10).空接口interface{}没有任何方法,所有所有类型都实现了空接口

package main

import(
    "fmt"
)

//空接口
type T interface{

}
func main()  {
    var t T = stu //ok
    fmt.Println(t)  //{}

    var t2 interface{} = stu
    fmt.Println(t2) //{}
    var num float64 = 2.33
    t2 = num
    fmt.Println(t2)// 2.33
}

5.接口案例

实现对Hero结构体切片的排序:sort.Sort(data.Interface) 

package main

import (
    "fmt"
    "sort"
    "math/rand"
)

//实现对Hero结构体切片的排序:sort.Sort(data interface)
//1.声明一个Here结构体
type Hero struct {
    Name string
    Age int
}

//2.声明一个Here结构体切片
type HeroSlice []Hero

//3.实现接口Interface接口
// func Sort(data Interface)
/*
type Interface interface {
    // Len方法返回集合中的元素个数
    Len() int
    // Less方法报告索引i的元素是否比索引j的元素小
    Less(i, j int) bool
    // Swap方法交换索引i和j的两个元素
    Swap(i, j int)
}
*/
func (hs HeroSlice) Len() int {
    return len(hs)
}
//Less就是决定你使用什么标准进行排序
//1. 按照Here的年龄从小到大排序
//2.修改成对名字进行排序
func (hs HeroSlice)  Less(i, j int) bool {
    // 1. 按照Here的年龄从小到大排序
    // return hs[i].Age < hs[j].Age //升序
    // 2.修改成对名字进行排序
    return hs[i].Name < hs[j].Name  //升序
}
func (hs HeroSlice)  Swap(i, j int) {
    //交换
    // temp := hs[i]
    // hs[i] = hs[j]
    // hs[j] = temp
    // 上面的三句等价于下面的一句
    hs[i], hs[j] = hs[j], hs[i]
}

func main()  {
    //先定义一个数组/切片
    var intSlice = []int{12, -1, 4, 2, 15}
    //要求对intSlice切片进行排序
    //1.冒泡排序
    //2.使用系统提供的方法
    sort.Ints(intSlice)
    fmt.Println(intSlice)

    //对结构体进行排序
    //1.冒泡排序
    //2.也可以使用系统提供的方法

    //对结构体切片进行排序
    var heroes HeroSlice
    for i := 0; i < 10; i++ {
        hero := Hero {
            Name : fmt.Sprintf("英雄%d", rand.Intn(100)),
            Age : rand.Intn(100),
        }
        //将hero append 到heroes切片
        heroes = append(heroes, hero)
    }

    //排序前的顺序
    for _, v := range heroes {
        fmt.Println(v)
    }
    //调用sort.Sort
    sort.Sort(heroes)

    //排序后的顺序
    fmt.Println("排序后")
    for _, v := range heroes {
        fmt.Println(v)
    }
}

 实现对Student结构体切片按照成绩升序进行排序

package main

import (
    "fmt"
    "math/rand"
    "sort"
)

//实现对Student结构体切片按照成绩升序进行排序
//1.声明一个Student结构体
type Student struct{
    Name string
    Age int
    Score float64
}

//2.声明一个Student切片
type StuSlice []Student

//3.实现接口Interface接口
// func Sort(data Interface)
/*
type Interface interface {
    // Len方法返回集合中的元素个数
    Len() int
    // Less方法报告索引i的元素是否比索引j的元素小
    Less(i, j int) bool
    // Swap方法交换索引i和j的两个元素
    Swap(i, j int)
}
*/
func (stu StuSlice) Len() int  {
    return len(stu)
}
func (stu StuSlice)Less(i, j int) bool  {
    return stu[i].Score < stu[j].Score
}
func (stu StuSlice) Swap(i, j int)  {
    stu[i], stu[j] = stu[j], stu[i]
}

func main()  {
    //创建一个Student切片实例
    var stues StuSlice
    for i := 0; i <=10 ; i++ {
        stu := Student{
            Name : fmt.Sprintf("学生%v", rand.Intn(100)),
            Age : rand.Intn(100),
            Score : float64(rand.Intn(100)),
        }
        //把stu append 到stues结构体实例变量中
        stues = append(stues, stu)
    }

    //排序前数据
    for _,v := range stues {
        fmt.Println(v)
    }
    //排序后数据
    fmt.Println("排序后数据")
    sort.Sort(stues)
    for _,v := range stues {
        fmt.Println(v)
    }
}

6.接口和继承的比较

package main

import(
    "fmt"
)

//声明一个鸟儿接口
type BridAble interface {
    Flying()    
}
//声明一个鱼儿接口
type FishAble interface {
    Swimming()  
}

//Monkey
type Monkey struct{
    Name string
}

func (this *Monkey) climbing() {
    fmt.Println(this.Name, "会爬树")
}

//LittleMonkey结构体
type LittleMonkey struct{
    Monkey // 继承
}

//让LittleMonkey实现BridAble.Flying
func (this *LittleMonkey) Flying() {
    fmt.Println(this.Name, "通过学习,学会了飞翔")
}
//让LittleMonkey实现FishAble.Swimming
func (this *LittleMonkey) Swimming() {
    fmt.Println(this.Name, "通过学习,学会了游泳")
}
func main()  {
    //创建一个LitteMonkey实例
    littleMonkey := LittleMonkey{
        Monkey {
            Name : "猴子1",
        },
    }
    littleMonkey.climbing()
    littleMonkey.Flying()
    littleMonkey.Swimming()
}

对上面代码的小结 :

(1).当 A 结构体继承了 B 结构体,那么 A 结构就自动的继承了 B 结构体的字段和方法,并且可以直接使用

(2 ).当 A 结构体需要扩展功能同时不希望去破坏继承关系,则可以去实现某个接口即可,因此可以认为:实现接口是对继承机制的补充

图示说明: 

接口和继承解决的解决的问题不同

        继承的价值主要在于:解决代码的复用性和可维护性

        接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法

接口比继承更加灵活 Person Student , BirdAble LitdeMonkev

接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足 like - a的关系

接口在一定程度上实现代码解藕

[上一节][go学习笔记.第十章.面向对象编程] 9.面向对象的三大特性-继承 

[下一节][go学习笔记.第十章.面向对象编程] 11.面向对象的三大特性-多态 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值