Golang的继承模拟实例


Posted in Golang onJune 30, 2021

1.前言

面向对象编程的三大特性:封装、继承、多态。可见继承是面向对象程序设计中一个重要的概念。Go 作为面向对象的编程语言,自然也支持继承。

比较特殊的是 Go 实现继承的方式与其他传统 OOP 语言所有不同,不像 C++ 有专门的继承语法,或者像 Java 中有专门的关键字 extends。

C++ 的继承:

// 基类
class Animal {
public:
    void eat(); 
	void sleep();
};


// 子类
class Dog : public Animal {
public:
    void bark();
};

Java 的继承:

// 基类
public class Animal {
	public void eat(){};
	public void sleep(){};
}
// 子类
public class Dog extends Animal {
	public void bark(){};
}

2.嵌入式继承机制

Go 使用匿名嵌套实现继承。

我们用很容易理解的动物-猫来举例子。

type Animal struct {
	Name string
}
func (a *Animal) Eat() {
	fmt.Printf("%v is eating", a.Name)
	fmt.Println()
}
type Cat struct {
	Animal
}
cat := &Cat{
	Animal: Animal{
		Name: "cat",
	},
}
cat.Eat() // cat is eating

首先,我们实现了一个 Animal 的结构体,代表动物类。并声明了 Name 字段,用于描述动物的名字。

然后,实现了一个以 Animal 为 receiver 的 Eat 方法,来描述动物进食的行为。

最后,声明了一个 Cat 结构体,组合了 Cat 字段。再实例化一个猫,调用Eat方法,可以看到会正常的输出。

可以看到,Cat 结构体本身没有 Name 字段,也没有去实现 Eat() 方法。唯一有的就是匿名嵌套的方式继承了 Animal 父类,至此,我们证明了 Go 通过匿名嵌套的方式实现了继承。

上面是嵌入类型实例,同样地也可以嵌入类型指针。

type Cat struct {
	*Animal
}
cat := &Cat{
	Animal: &Animal{
		Name: "cat",
	},
}

3.嵌入式继承机制的的局限

相比于 C++ 和 Java, Go 的继承机制的作用是非常有限的,因为没有抽象方法,有很多的设计方案可以在 C++ 和 Java 中轻松实现,但是 Go 的继承却不能完成同样的工作。

package main
import "fmt"
// Animal 动物基类
type Animal struct {
	name string
}
func (a *Animal) Play() {
	fmt.Println(a.Speak())
}
func (a *Animal) Speak() string {
	return fmt.Sprintf("my name is %v", a.name)
}
func (a *Animal) Name() string {
	return a.name
}
// Dog 子类狗
type Dog struct {
	Animal
	Gender string
}
func (d *Dog) Speak() string {
	return fmt.Sprintf("%v and my gender is %v", d.Animal.Speak(), d.Gender)
}
func main() {
	d := Dog{
		Animal: Animal{name: "Hachiko"},
		Gender:  "male",
	}
	fmt.Println(d.Name())
	fmt.Println(d.Speak())
	d.Play() // Play() 中调用的是基类 Animal.Speak() 方法,而不是 Dog.Speak()
}

运行输出:

Hachiko
my name is Hachiko and my gender is male
my name is Hachiko

上面的例子中,Dog 类型重写了 Speak() 方法。然而如果父类型 Animal 有另外一个方法 Play() 调用 Speak() 方法,但是 Dog 没有重写 Play() 的时候,Dog 类型的 Speak() 方法则不会被调用,因为 Speak() 方法不是抽象方法,此时继承无法实现多态。

4.使用接口封装方法

为了解决上面的问题,我们应该使用接口封装方法,通过实现接口方法来实现多态。

package main
import (
    "fmt"
)
type Animal interface {
    Name() string
    Speak() string
    Play()
}
type Dog struct {
    name string
    gender string
}
func (d *Dog) Play() {
    fmt.Println(d.Speak())
}
func (d *Dog) Speak() string {
    return fmt.Sprintf("my name is %v and my gender is %v", d.name, d.gender)
}
func (d *Dog) Name() string {
    return d.name
}
func Play(a Animal) {
    a.Play()
}
func main() {
    d :=&Dog{"Hachiko", "male"}
    fmt.Println(d.Name())
    fmt.Println(d.Speak())
    Play(d)
}

运行输出:

Hachiko
my name is Hachiko and my gender is male
my name is Hachiko and my gender is male

注意:Go 中某个类型需要实现接口中的所有方法才算作实现了接口。

5.小结

如果一个 struct 嵌套了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的属性和方法,从而实现继承。

如果一个 struct 嵌套了另一个有名的结构体,那么这个模式叫做组合。

如果一个 struct 嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的属性和方法,从而实现多重继承。

本篇文章就到这里了,希望能帮助到你,也希望您能多多关注三水点靠木的更多内容!

Golang 相关文章推荐
Go语言-为什么返回值为接口类型,却返回结构体
Apr 24 Golang
win10下go mod配置方式
Apr 25 Golang
go原生库的中bytes.Buffer用法
Apr 25 Golang
Go语言中break label与goto label的区别
Apr 28 Golang
Golang 如何实现函数的任意类型传参
Apr 29 Golang
goland 设置project gopath的操作
May 06 Golang
Golang实现AES对称加密的过程详解
May 20 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
golang生成vcf通讯录格式文件详情
Mar 25 Golang
golang为什么要统一错误处理
Apr 03 Golang
Go语言入门exec的基本使用
May 20 Golang
go select编译期的优化处理逻辑使用场景分析
Go 语言下基于Redis分布式锁的实现方式
Jun 28 #Golang
go语言使用Casbin实现角色的权限控制
Go语言设计模式之结构型模式
浅谈Go语言多态的实现与interface使用
Jun 16 #Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 #Golang
Go遍历struct,map,slice的实现
Jun 13 #Golang
You might like
几种有用的变型 PHP中循环语句的用法介绍
2012/01/30 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
Aster vs KG BO3 第二场2.18
2021/03/10 DOTA
jquery控制listbox中项的移动并排序
2009/11/12 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
使用jquery清空、复位整个输入域
2015/04/02 Javascript
jQuery对JSON数据进行排序输出的方法
2015/06/24 Javascript
浅析$.getJSON异步请求和同步请求
2016/06/06 Javascript
关于两个jQuery(js)特效冲突的bug的解决办法
2016/09/04 Javascript
BootStrap树状图显示功能
2016/11/24 Javascript
快速实现JS图片懒加载(可视区域加载)示例代码
2017/01/04 Javascript
js按条件生成随机json:randomjson实现方法
2017/04/07 Javascript
echarts整合多个类似option的方法实例
2018/07/10 Javascript
基于vue-upload-component封装一个图片上传组件的示例
2018/10/16 Javascript
深入分析jQuery.one() 函数
2020/06/03 jQuery
python使用在线API查询IP对应的地理位置信息实例
2014/06/01 Python
在MAC上搭建python数据分析开发环境
2016/01/26 Python
python 自定义异常和异常捕捉的方法
2018/10/18 Python
pycharm解决关闭flask后依旧可以访问服务的问题
2020/04/03 Python
Python如何把十进制数转换成ip地址
2020/05/25 Python
Python 使用 PyQt5 开发的关机小工具分享
2020/07/16 Python
Python unittest如何生成HTMLTestRunner模块
2020/09/08 Python
关于探究python中sys.argv时遇到的问题详解
2021/02/23 Python
德国低价购买灯具和家具网站:Style-home.de
2016/11/25 全球购物
美国百年历史早餐食品供应商:Wolferman’s
2017/01/18 全球购物
Banana Republic欧盟:美国都市简约风格的代表品牌
2018/05/09 全球购物
Pandora西班牙官方商店:PandoraShop.es
2020/10/05 全球购物
怎么写有吸引力的自荐信
2013/11/17 职场文书
企业党员公开承诺书
2014/03/26 职场文书
三关爱志愿服务活动方案
2014/08/17 职场文书
考研英语辞职信
2015/05/13 职场文书
征求意见函
2015/06/05 职场文书
vue3中的组件间通信
2021/03/31 Vue.js
详解redis在微服务领域的贡献
2021/10/16 Redis
草系十大最强宝可梦,纸片人上榜,榜首大家最熟悉
2022/03/18 日漫
Python 避免字典和元组的多重嵌套问题
2022/07/15 Python