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:垃圾回收GC触发条件详解
Apr 24 Golang
go原生库的中bytes.Buffer用法
Apr 25 Golang
go设置多个GOPATH的方式
May 05 Golang
Goland使用Go Modules创建/管理项目的操作
May 06 Golang
golang 实现并发求和
May 08 Golang
Go语言实现Snowflake雪花算法
Jun 08 Golang
入门学习Go的基本语法
Jul 07 Golang
go开发alertmanger实现钉钉报警
Jul 16 Golang
go goroutine 怎样进行错误处理
Jul 16 Golang
Go语言基础切片的创建及初始化示例详解
Nov 17 Golang
Go中使用gjson来操作JSON数据的实现
Aug 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
最新用php获取谷歌PR值算法,附上php查询PR值代码示例
2011/12/25 PHP
php中让上传的文件大小在上传前就受限制的两种解决方法
2013/06/24 PHP
php实现网站顶踩功能的完整前端代码
2015/07/19 PHP
PHP用正则匹配form表单中所有元素的类型和属性值实例代码
2017/02/28 PHP
Laravel框架中Blade模板的用法示例
2017/08/30 PHP
js innerHTML 的一些问题的解决方法
2008/06/22 Javascript
Ext第一周 史上最强学习笔记---GridPanel(基础篇)
2008/12/29 Javascript
Javascript 日期处理之时区问题
2009/10/08 Javascript
parseInt parseFloat js字符串转换数字
2010/08/01 Javascript
intro.js 页面引导简单用法 分享
2013/08/06 Javascript
Javascript实现禁止输入中文或英文的例子
2014/12/09 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
使用js画图之圆、弧、扇形
2015/01/12 Javascript
详解JavaScript ES6中的Generator
2015/07/28 Javascript
Javascript简单实现面向对象编程继承实例代码
2015/11/27 Javascript
node.js实现爬虫教程
2020/08/25 Javascript
微信小程序显示倒计时功能示例【测试可用】
2018/12/03 Javascript
js定义类的方法示例【ES5与ES6】
2019/07/30 Javascript
Node.js API详解之 tty功能与用法实例分析
2020/04/27 Javascript
Vue实现一种简单的无限循环滚动动画的示例
2021/01/10 Vue.js
在Python中操作字典之update()方法的使用
2015/05/22 Python
Python实现树的先序、中序、后序排序算法示例
2017/06/23 Python
Python统计纯文本文件中英文单词出现个数的方法总结【测试可用】
2018/07/25 Python
利用Django-environ如何区分不同环境
2018/08/26 Python
python环境路径配置以及命令行运行脚本
2019/04/02 Python
Python面向对象程序设计类的多态用法详解
2019/04/12 Python
Python进阶:生成器 懒人版本的迭代器详解
2019/06/29 Python
在python下实现word2vec词向量训练与加载实例
2020/06/09 Python
Python爬虫爬取博客实现可视化过程解析
2020/06/29 Python
python包的导入方式总结
2021/03/02 Python
详解淘宝H5 sign加密算法
2020/08/25 HTML / CSS
求职信范文英文版
2014/01/05 职场文书
建筑设计专业求职自我评价
2014/03/02 职场文书
《沉香救母》教学反思
2014/04/19 职场文书
2015年前台文员工作总结
2015/05/18 职场文书
redis实现共同好友的思路详解
2021/05/26 Redis