当前位置: 首页 > news >正文

Go 接口和多态

在讲解具体的接口之前,先看如下问题。

使用面向对象的方式,设计一个加减的计算器

代码如下:

package mainimport "fmt"//父类,这是结构体
type Operate struct {num1 intnum2 int
}//加法子类,这是结构体type Add struct {Operate
}//减法子类,这是结构体type Sub struct {Operate
}//加法子类的方法
func (a *Add) Result() int {return a.num1 + a.num2
}
可以看到ADD里面是用父类结构体的,然后直接返回num1+num2就行了
//减法子类的方法
func (s *Sub) Result() int {return s.num1 - s.num2
}
可以看到Sub里面是用父类结构体的,然后直接返回num1-num2就行了
//方法调用
func main0201() {//创建加法对象//var a Add//a.num1 = 10//a.num2 = 20//v := a.Result()//fmt.Println(v)
//可以看到调用起来还是很简单的,直接给父类结构体的属性赋值,然后调用加法的方法就行。//创建减法对象var s Subs.num1 = 10s.num2 = 20v := s.Result()fmt.Println(v)
}
//可以看到调用起来还是很简单的,直接给父类结构体的属性赋值,然后调用减法的方法就行

以上实现非常简单,但是有个问题,在main()函数中,当我们想使用减法操作时,创建减法类的对象,调用其对应的减法的方法。但是,有一天,系统需求发生了变化,要求使用加法,不再使用减法,那么需要对main()函数中的代码,做大量的修改。将原有的代码注释掉,创建加法的类对象,调用其对应的加法的方法。有没有一种方法,让main()函数,只修改很少的代码就可以解决该问题呢?有,要用到接下来给大家讲解的接口的知识点。

一、 什么是接口

接口就是一种规范与标准,在生活中经常见接口,例如:笔记本电脑的USB接口,可以将任何厂商生产的鼠标与键盘,与电脑进行链接。为什么呢?原因就是,USB接口将规范和标准制定好后,各个生产厂商可以按照该标准生产鼠标和键盘就可以了。

在程序开发中,接口只是规定了要做哪些事情,干什么。具体怎么做,接口是不管的。这和生活中接口的案例也很相似,例如:USB接口,只是规定了标准,但是不关心具体鼠标与键盘是怎样按照标准生产的.

在企业开发中,如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口告诉开发人员你需要实现那些功能。

二、 接口定义

接口定义的语法如下:

//先定义接口 一般以er结尾 根据接口实现功能
type Humaner interface {//方法 方法的声明sayhi()
}

怎样具体实现接口中定义的方法呢?

//Student的结构体
type student11 struct {name  stringage   intscore int
}
//Student的打印方法
func (s *student11)sayhi()  {fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score)
}
//teacher11的结构体
type teacher11 struct {name    stringage     intsubject string
}
//teacher11的方法
func (t *teacher11)sayhi()  {fmt.Printf("大家好,我是%s,今年%d岁,我的学科是%s\n",t.name,t.age,t.subject)
}

具体的调用如下:

func main() {//接口是一种数据类型 可以接收满足对象的信息//接口是虚的  方法是实的//接口定义规则  方法实现规则//接口定义的规则  在方法中必须有定义的实现var h Humanerstu := student11{"小明",18,98}//stu.sayhi()//将对象信息赋值给接口类型变量h = &stuh.sayhi()
//直接将Student的对象赋值给了h接口,然后就能实现方法的调用tea := teacher11{"老王",28,"物理"}//tea.sayhi()//将对象赋值给接口 必须满足接口中的方法的声明格式h = &teah.sayhi()
}

只要类(结构体)实现对应的接口,那么根据该类创建的对象,可以赋值给对应的接口类型。

接口的命名习惯以er结尾。

三、 多态

接口有什么好处呢?实现多态。

多态就是同一个接口,使用不同的实例而执行不同操作

所谓多态指的是多种表现形式,如下图所示:
在这里插入图片描述

使用接口实现多态的方式如下:

package mainimport "fmt"//先定义接口  一般以er结尾  根据接口实现功能
type Humaner1 interface {//方法  方法的声明sayhi()}//student12的结构体
type student12 struct {name  stringage   intscore int
}
//student12的方法
func (s *student12)sayhi()  {fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score)
}
//teacher12的结构体
type teacher12 struct {name    stringage     intsubject string
}
//teacher12的方法
func (t *teacher12)sayhi()  {fmt.Printf("大家好,我是%s,今年%d岁,我的学科是%s\n",t.name,t.age,t.subject)
}//多态的实现
//将接口作为函数参数  实现多态
func sayhello(h Humaner1)  {h.sayhi()
}func main() {stu := student12{"小明",18,98}//调用多态函数sayhello(&stu)tea := teacher12{"老王",28,"Go"}sayhello(&tea)
}

关于接口的定义,以及使用接口实现多态,但是多态有什么好处呢?现在还是以开始提出的计算器案例给大家讲解一下。

四、多态案例

使用多态的功能,实现一个加减计算器。完整代码如下:

package mainimport "fmt"// 定义接口
type Opter interface {// 方法声明Result() int
}// 父类
type Operate struct {num1 intnum2 int
}// 加法子类
type Add struct {Operate
}// 加法子类的方法
func (a *Add) Result() int {return a.num1 + a.num2
}// 减法子类
type Sub struct {Operate
}// 减法子类的方法
func (s *Sub) Result() int {return s.num1 - s.num2
}// 多态实现
func Result(o Opter) {v := o.Result()fmt.Println(v)
}// 上面是定义的方法
func main() {//创建加法对象//var a Add//a.num1 = 10//a.num2 = 20//v := a.Result()//fmt.Println(v)//2.通过接口实现//var o Opter//var a Add = Add{Operate{10, 20}}//o = &a//value := o.Result()//fmt.Println(value)//3.多态实现var a Add = Add{Operate{10, 20}}Result(&a)var s Sub = Sub{Operate{10, 20}}Result(&s)
}30
-10

四、 接口继承与转换

接口也可以实现继承:

// 先定义接口  一般以er结尾  根据接口实现功能
type Humaner2 interface { //子集//方法  方法的声明sayhi()
}type Personer interface { //超集Humaner2 //继承sayhi()sing(string)
}type student13 struct {name  stringage   intscore int
}func (s *student13) sayhi() {fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n", s.name, s.age, s.score)
}func (s *student13) sing(name string) {fmt.Println("我为大家唱首歌", name)
}func main() {//接口类型变量定义var h Humaner2var stu student13 = student13{"小吴", 18, 59}h = &stuh.sayhi()//接口类型变量定义var p Personerp = &stup.sayhi()p.sing("大碗面")
}大家好,我是小吴,今年18岁,我的成绩59分
大家好,我是小吴,今年18岁,我的成绩59

接口继承后,可以实现“超集”接口转换“子集”接口,代码如下:

package mainimport "fmt"// 先定义接口  一般以er结尾  根据接口实现功能
type Humaner2 interface { //子集//方法  方法的声明sayhi()
}type Personer interface { //超集Humaner2 //继承sayhi()sing(string)
}type student13 struct {name  stringage   intscore int
}func (s *student13) sayhi() {fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n", s.name, s.age, s.score)
}func (s *student13) sing(name string) {fmt.Println("我为大家唱首歌", name)
}func main() {//接口类型变量定义var h Humaner2 //子集var p Personer //超集var stu student13 = student13{"小吴", 18, 59}p = &stu//将一个接口赋值给另一个接口//超集中包含所有子集的方法h = p //okh.sayhi()//子集不包含超集//不能将子集赋值给超集//p = h  //err//p.sayhi()//p.sing("大碗面")
}

五、 空接口

空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值。例如:

func test1() {fmt.Println("test")
}func main() {// 空接口类型的切片var i []interface{}fmt.Printf("%T\n", i)i = append(i, 1, 3.14, "aaa", test1)fmt.Println(i)for idx := 0; idx < len(i); idx++ {fmt.Println(i[idx])}
}[]interface {}
[1 3.14 aaa 0xd5420]
1                   
3.14                
aaa                 
0xd5420   
http://www.lryc.cn/news/162170.html

相关文章:

  • Git忽略文件的几种方法,以及.gitignore文件的忽略规则
  • C语言——指针进阶(2)
  • 【汇编中的寄存器分类与不同寄存器的用途】
  • 基于文本提示的图像目标检测与分割实践
  • 【4-5章】Spark编程基础(Python版)
  • 04 卷积神经网络搭建
  • 【hadoop运维】running beyond physical memory limits:正确配置yarn中的mapreduce内存
  • 数据结构--6.5二叉排序树(插入,查找和删除)
  • 无需公网IP,在家SSH远程连接公司内网服务器「cpolar内网穿透」
  • Java工具类
  • makefile之使用函数wildcard和patsubst
  • 算法通关村第十八关——排列问题
  • 基于STM32设计的生理监测装置
  • Go-Python-Java-C-LeetCode高分解法-第五周合集
  • 【前端知识】前端加密算法(base64、md5、sha1、escape/unescape、AES/DES)
  • leetcode 925. 长按键入
  • [CMake教程] 循环
  • Mojo安装使用初体验
  • 艺术与AI:科技与艺术的完美融合
  • Android常用的工具“小插件”——Widget机制
  • 探索在云原生环境中构建的大数据驱动的智能应用程序的成功案例,并分析它们的关键要素。
  • jupyter 添加中文选项
  • 系列十、Java操作RocketMQ之批量消息
  • leetcode1两数之和
  • 近年GDC服务器分享合集(四): 《火箭联盟》:为免费游玩而进行的扩展
  • android反射详解
  • Python 反射和动态执行
  • 计算机网络常见端口号
  • SpringBoot / Vue 对SSE的基本使用(简单上手)
  • Qt串口基本设置与协议收发