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语言切片前或中间插入项与内置copy()函数详解
Apr 27 Golang
Golang全局变量加锁的问题解决
May 08 Golang
go语言中http超时引发的事故解决
Jun 02 Golang
Golang中异常处理机制详解
Jun 08 Golang
Go语言设计模式之结构型模式
Jun 22 Golang
go语言使用Casbin实现角色的权限控制
Jun 26 Golang
Go语言基础知识点介绍
Jul 04 Golang
Golang中channel的原理解读(推荐)
Oct 16 Golang
Go语言特点及基本数据类型使用详解
Mar 21 Golang
Go语言grpc和protobuf
Apr 13 Golang
Golang入门之计时器
May 04 Golang
Go语言怎么使用变长参数函数
Jul 15 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二维数组的去重问题解析
2011/07/17 PHP
php对csv文件的读取,写入,输出下载操作详解
2013/08/10 PHP
php使用websocket示例详解
2014/03/12 PHP
php安装php_rar扩展实现rar文件读取和解压的方法
2016/11/17 PHP
php file_get_contents取文件中数组元素的方法
2017/04/01 PHP
Laravel中为什么不使用blpop取队列详析
2018/08/01 PHP
Javascript hasOwnProperty 方法 & in 关键字
2008/11/26 Javascript
读jQuery之四(优雅的迭代)
2011/06/20 Javascript
jQuery之ajax删除详解
2014/02/27 Javascript
介绍一个简单的JavaScript类框架
2015/06/24 Javascript
30分钟快速掌握Bootstrap框架
2016/05/24 Javascript
利用JavaScript判断浏览器类型及版本
2016/08/23 Javascript
vue2.0 中#$emit,$on的使用详解
2017/06/07 Javascript
Vue点击切换颜色的方法
2018/09/13 Javascript
js实现下拉框二级联动
2018/12/04 Javascript
react-native 实现购物车滑动删除效果的示例代码
2021/01/15 Javascript
django使用html模板减少代码代码解析
2017/12/12 Python
对python pandas读取剪贴板内容的方法详解
2019/01/24 Python
Python实现判断一个整数是否为回文数算法示例
2019/03/02 Python
pyqt5 使用label控件实时显示时间的实例
2019/06/14 Python
Django密码系统实现过程详解
2019/07/19 Python
python打印n位数“水仙花数”(实例代码)
2019/12/25 Python
python连接打印机实现打印文档、图片、pdf文件等功能
2020/02/07 Python
python加密解密库cryptography使用openSSL生成的密匙加密解密
2020/02/11 Python
python对指定字符串逆序的6种方法(小结)
2020/04/02 Python
python中matplotlib实现随鼠标滑动自动标注代码
2020/04/23 Python
美国花园雕像和家居装饰网上商店:Design Toscano
2019/03/09 全球购物
德国2018年度最佳在线药房:Bodfeld Apotheke
2019/11/04 全球购物
俄罗斯在线服装店:STOLNIK
2021/03/07 全球购物
小学教师自我鉴定范文
2014/03/20 职场文书
财务部会计岗位职责
2015/02/03 职场文书
小学家长意见怎么写
2015/06/03 职场文书
公司员工奖惩制度
2015/08/04 职场文书
【海涛DOTA】D-cup邀请赛NV.cn vs DT.Love
2022/04/01 DOTA
前端JS获取URL参数的4种方法总结
2022/04/05 Javascript
浅谈Redis缓冲区机制
2022/06/05 Redis