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


    1.基本介绍

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

    2.快速入门

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. // 声明一个接口
    6. type Usb interface {
    7.     //声明了两个没有实现的方法
    8.     Start()
    9.     Stop()
    10. }
    11. //声明一个结构体,实现Usb方法
    12. type Phone struct{
    13. }
    14. func (p Phone) Start()  {
    15.     fmt.Println("手机开始工作...")
    16. }
    17. func (p Phone) Stop()  {
    18.     fmt.Println("手机停止工作...")
    19. }
    20. //相机实现Usb方法
    21. type Camera struct{
    22. }
    23. func (c Camera) Start()  {
    24.     fmt.Println("相机开始工作...")
    25. }
    26. func (c Camera) Stop()  {
    27.     fmt.Println("相机停止工作...")
    28. }
    29. //计算机
    30. type Computer struct{
    31. }
    32. //编写一个方法Working, 接收一个Usb接口类型变量
    33. //实现了Usb接口(就是指实现了Usb接口声明的所有方法)
    34. func (c Computer) Working(usb Usb)  {
    35.     //通过Usb接口变量来调用Start,Stop方法
    36.     usb.Start()
    37.     usb.Stop()
    38. }
    39. func main()  {
    40.     //先创建结构体变量
    41.     computer := Computer{}
    42.     phone := Phone{}
    43.     camera := Camera{}
    44.     //关键点
    45.     computer.Working(phone)
    46.     computer.Working(camera)
    47. }
    48. 手机开始工作...
    49. 手机停止工作...
    50. 相机开始工作...
    51. 相机停止工作...

    接口概念的再说明

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

    3.基本语法

    type 接口名 interface {

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

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

    实现接口的方法:

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

            //方法实现

    }

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

            //方法实现

    }

    小节说明

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

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

    应用场景

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

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

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type AInterface interface{
    6.     Say()
    7. }
    8. type Student struct{
    9.     Name string
    10. }
    11. func (stu Student) Say(){
    12.     fmt.Println("Stu Say()")
    13. }
    14. func main()  {
    15.     var stu Student //结构体变量,实现了Say(),也就实现了AInterface接口
    16.     var a AInterface = stu
    17.     a.Say()
    18. }

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

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

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

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

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type integer int
    6. func (i integer) Say()  {
    7.     fmt.Println("i integer, i=", i)
    8. }
    9. func main()  {
    10.     var i integer = 10
    11.     var b AInterface = i
    12.     b.Say()//i integer, i= 10
    13. }

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

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type AInterface interface{
    6.     Say()
    7. }
    8. type BInterface interface{
    9.     Hello()
    10. }
    11. type Monster struct{
    12. }
    13. func (m Monster) Say() {
    14.     fmt.Println("Monster Say()")
    15. }
    16. func (m Monster) Hello() {
    17.     fmt.Println("Monster Hello()")
    18. }
    19. func main()  {
    20.     //Monster实现了AInterface,BInterface
    21.     var monster Monster
    22.     var a1 AInterface = monster
    23.     var b1 BInterface = monster
    24.     a1.Say()
    25.     b1.Hello()
    26. }

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

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

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. type BInterface interface{
    6.     test01()
    7. }
    8. type CInterface interface{
    9.     test02()
    10. }
    11. type AInterface interface{
    12.     BInterface
    13.     CInterface
    14.     test03()
    15. }
    16. //如果需要实现AInterface,就需要把BInterface,CInterface额方法都实现
    17. type Stu struct{
    18. }
    19. func (stu Stu) test01() {
    20.    
    21. }
    22. func (stu Stu) test02() {
    23.    
    24. }
    25. func (stu Stu) test03() {
    26.    
    27. }
    28. func main()  {
    29.     var stu Stu
    30.     var a AInterface = stu
    31.     a.test01()
    32. }

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

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

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. //空接口
    6. type T interface{
    7. }
    8. func main()  {
    9.     var t T = stu //ok
    10.     fmt.Println(t)  //{}
    11.     var t2 interface{} = stu
    12.     fmt.Println(t2) //{}
    13.     var num float64 = 2.33
    14.     t2 = num
    15.     fmt.Println(t2)// 2.33
    16. }

    5.接口案例

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

    1. package main
    2. import (
    3.     "fmt"
    4.     "sort"
    5.     "math/rand"
    6. )
    7. //实现对Hero结构体切片的排序:sort.Sort(data interface)
    8. //1.声明一个Here结构体
    9. type Hero struct {
    10.     Name string
    11.     Age int
    12. }
    13. //2.声明一个Here结构体切片
    14. type HeroSlice []Hero
    15. //3.实现接口Interface接口
    16. // func Sort(data Interface)
    17. /*
    18. type Interface interface {
    19.     // Len方法返回集合中的元素个数
    20.     Len() int
    21.     // Less方法报告索引i的元素是否比索引j的元素小
    22.     Less(i, j int) bool
    23.     // Swap方法交换索引i和j的两个元素
    24.     Swap(i, j int)
    25. }
    26. */
    27. func (hs HeroSlice) Len() int {
    28.     return len(hs)
    29. }
    30. //Less就是决定你使用什么标准进行排序
    31. //1. 按照Here的年龄从小到大排序
    32. //2.修改成对名字进行排序
    33. func (hs HeroSlice)  Less(i, j int) bool {
    34.     // 1. 按照Here的年龄从小到大排序
    35.     // return hs[i].Age < hs[j].Age //升序
    36.     // 2.修改成对名字进行排序
    37.     return hs[i].Name < hs[j].Name  //升序
    38. }
    39. func (hs HeroSlice)  Swap(i, j int) {
    40.     //交换
    41.     // temp := hs[i]
    42.     // hs[i] = hs[j]
    43.     // hs[j] = temp
    44.     // 上面的三句等价于下面的一句
    45.     hs[i], hs[j] = hs[j], hs[i]
    46. }
    47. func main()  {
    48.     //先定义一个数组/切片
    49.     var intSlice = []int{12, -1, 4, 2, 15}
    50.     //要求对intSlice切片进行排序
    51.     //1.冒泡排序
    52.     //2.使用系统提供的方法
    53.     sort.Ints(intSlice)
    54.     fmt.Println(intSlice)
    55.     //对结构体进行排序
    56.     //1.冒泡排序
    57.     //2.也可以使用系统提供的方法
    58.     //对结构体切片进行排序
    59.     var heroes HeroSlice
    60.     for i := 0; i < 10; i++ {
    61.         hero := Hero {
    62.             Name : fmt.Sprintf("英雄%d", rand.Intn(100)),
    63.             Age : rand.Intn(100),
    64.         }
    65.         //将hero append 到heroes切片
    66.         heroes = append(heroes, hero)
    67.     }
    68.     //排序前的顺序
    69.     for _, v := range heroes {
    70.         fmt.Println(v)
    71.     }
    72.     //调用sort.Sort
    73.     sort.Sort(heroes)
    74.     //排序后的顺序
    75.     fmt.Println("排序后")
    76.     for _, v := range heroes {
    77.         fmt.Println(v)
    78.     }
    79. }

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

    1. package main
    2. import (
    3.     "fmt"
    4.     "math/rand"
    5.     "sort"
    6. )
    7. //实现对Student结构体切片按照成绩升序进行排序
    8. //1.声明一个Student结构体
    9. type Student struct{
    10.     Name string
    11.     Age int
    12.     Score float64
    13. }
    14. //2.声明一个Student切片
    15. type StuSlice []Student
    16. //3.实现接口Interface接口
    17. // func Sort(data Interface)
    18. /*
    19. type Interface interface {
    20.     // Len方法返回集合中的元素个数
    21.     Len() int
    22.     // Less方法报告索引i的元素是否比索引j的元素小
    23.     Less(i, j int) bool
    24.     // Swap方法交换索引i和j的两个元素
    25.     Swap(i, j int)
    26. }
    27. */
    28. func (stu StuSlice) Len() int  {
    29.     return len(stu)
    30. }
    31. func (stu StuSlice)Less(i, j int) bool  {
    32.     return stu[i].Score < stu[j].Score
    33. }
    34. func (stu StuSlice) Swap(i, j int)  {
    35.     stu[i], stu[j] = stu[j], stu[i]
    36. }
    37. func main()  {
    38.     //创建一个Student切片实例
    39.     var stues StuSlice
    40.     for i := 0; i <=10 ; i++ {
    41.         stu := Student{
    42.             Name : fmt.Sprintf("学生%v", rand.Intn(100)),
    43.             Age : rand.Intn(100),
    44.             Score : float64(rand.Intn(100)),
    45.         }
    46.         //把stu append 到stues结构体实例变量中
    47.         stues = append(stues, stu)
    48.     }
    49.     //排序前数据
    50.     for _,v := range stues {
    51.         fmt.Println(v)
    52.     }
    53.     //排序后数据
    54.     fmt.Println("排序后数据")
    55.     sort.Sort(stues)
    56.     for _,v := range stues {
    57.         fmt.Println(v)
    58.     }
    59. }

    6.接口和继承的比较

    1. package main
    2. import(
    3.     "fmt"
    4. )
    5. //声明一个鸟儿接口
    6. type BridAble interface {
    7.     Flying()    
    8. }
    9. //声明一个鱼儿接口
    10. type FishAble interface {
    11.     Swimming()  
    12. }
    13. //Monkey
    14. type Monkey struct{
    15.     Name string
    16. }
    17. func (this *Monkey) climbing() {
    18.     fmt.Println(this.Name, "会爬树")
    19. }
    20. //LittleMonkey结构体
    21. type LittleMonkey struct{
    22.     Monkey // 继承
    23. }
    24. //让LittleMonkey实现BridAble.Flying
    25. func (this *LittleMonkey) Flying() {
    26.     fmt.Println(this.Name, "通过学习,学会了飞翔")
    27. }
    28. //让LittleMonkey实现FishAble.Swimming
    29. func (this *LittleMonkey) Swimming() {
    30.     fmt.Println(this.Name, "通过学习,学会了游泳")
    31. }
    32. func main()  {
    33.     //创建一个LitteMonkey实例
    34.     littleMonkey := LittleMonkey{
    35.         Monkey {
    36.             Name : "猴子1",
    37.         },
    38.     }
    39.     littleMonkey.climbing()
    40.     littleMonkey.Flying()
    41.     littleMonkey.Swimming()
    42. }

    对上面代码的小结 :

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

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

    图示说明: 

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

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

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

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

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

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

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

  • 相关阅读:
    JavaScript逻辑题:输出1000之内的所有完数。所谓完数指的是:如果一个数恰好等于它的所有因子之和,这个数就称为完数。
    微信服务商模式(电商收付通)合单支付APIV3完整Demo,可直接使用,适用于(H5、JSAPI、H5、App、小程序)
    葡萄糖-聚乙二醇-巯基Glucose-PEG-Alkyne|葡萄糖-聚乙二醇-生物素Glucose-PEG-Biotin
    笔试刷题Day—1
    Linux-进程间通信
    P4630 [APIO2018] 铁人两项 (广义圆方树)
    PHP命令行脚本接收传入参数的三种方式
    python表白弹框
    安装TPDSS
    时间轮(Timing Wheel)案例和原理
  • 原文地址:https://blog.csdn.net/zhoupenghui168/article/details/125901643