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 02 Golang
golang interface判断为空nil的实现代码
Apr 24 Golang
golang正则之命名分组方式
Apr 25 Golang
golang中实现给gif、png、jpeg图片添加文字水印
Apr 26 Golang
Golang 实现超大文件读取的两种方法
Apr 27 Golang
解决Golang中goroutine执行速度的问题
May 02 Golang
go语言基础 seek光标位置os包的使用
May 09 Golang
golang 实用库gotable的具体使用
Jul 01 Golang
Go语言应该什么情况使用指针
Jul 25 Golang
Go语言读取txt文档的操作方法
Jan 22 Golang
Golang数据类型和相互转换
Apr 12 Golang
Go调用Rust方法及外部函数接口前置
Jun 14 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
Windows PHP5和Apache的安装与配置
2009/06/08 PHP
PHP生成迅雷、快车、旋风等软件的下载链接代码实例
2014/05/12 PHP
使用php的HTTP请求的库Requests实现美女图片墙
2015/02/22 PHP
PHP常见过waf webshell以及最简单的检测方法
2019/05/21 PHP
javascript下IE与FF兼容函数收集
2008/09/17 Javascript
javascript基础知识大集锦(二) 推荐收藏
2011/01/13 Javascript
使用js在页面中绘制表格核心代码
2013/09/16 Javascript
js 一个关于图片onload加载的事
2013/11/10 Javascript
jquery.post用法关于type设置问题补充
2014/01/03 Javascript
jquery 选取方法都有哪些
2014/05/18 Javascript
JavaScript对象学习小结
2015/09/02 Javascript
JavaScript实现搜索框的自动完成功能(一)
2016/02/25 Javascript
详解jQuery UI库中文本输入自动补全功能的用法
2016/04/23 Javascript
JS常用函数和常用技巧小结
2016/10/15 Javascript
Angularjs的Controller间通信机制实例分析
2016/11/07 Javascript
从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例
2017/04/13 Javascript
Angular4学习笔记之准备和环境搭建项目
2017/08/01 Javascript
vue+element UI实现树形表格带复选框的示例代码
2019/04/16 Javascript
使用Vue.observable()进行状态管理的实例代码详解
2019/05/26 Javascript
Python使用os模块和fileinput模块来操作文件目录
2016/01/19 Python
python实现稀疏矩阵示例代码
2017/06/09 Python
对Python中plt的画图函数详解
2018/11/07 Python
实例讲解Python3中abs()函数
2019/02/19 Python
基于Python的PIL库学习详解
2019/05/10 Python
python爬取王者荣耀全皮肤的简单实现代码
2020/01/31 Python
Stefania Mode英国:奢华设计师和时尚服装
2017/10/23 全球购物
NBA德国官方网上商店:NBA Store德国
2018/04/13 全球购物
中学教师岗位职责
2013/11/26 职场文书
最新会计专业求职信范文
2014/01/28 职场文书
幼儿园学前班幼儿评语
2014/12/29 职场文书
项目经理岗位职责
2015/01/31 职场文书
vue实现同时设置多个倒计时
2021/05/20 Vue.js
解决pytorch-gpu 安装失败的记录
2021/05/24 Python
如何用python清洗文件中的数据
2021/06/18 Python
世界十大狙击步枪排行榜
2022/03/20 杂记
Linux系统下MySQL配置主从分离的步骤
2022/03/21 MySQL