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 29 Golang
golang slice元素去重操作
Apr 30 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
Golang Gob编码(gob包的使用详解)
May 07 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
golang fmt格式“占位符”的实例用法详解
Jul 04 Golang
golang语言指针操作
Apr 14 Golang
Golang日志包的使用
Apr 20 Golang
Golang并发工具Singleflight
May 06 Golang
Go gRPC进阶教程gRPC转换HTTP
Jun 16 Golang
Go gorilla/sessions库安装使用
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 setcookie() cannot modify header information 的解决方法
2009/01/09 PHP
PHP随机生成唯一HASH值自定义函数
2015/04/20 PHP
PHP错误处理函数
2016/04/03 PHP
thinkphp5 + ajax 使用formdata提交数据(包括文件上传) 后台返回json完整实例
2020/03/02 PHP
Textarea与懒惰渲染实现代码
2012/01/04 Javascript
使用jQuery validate 验证注册表单实例演示
2013/03/25 Javascript
js克隆对象、数组的常用方法介绍
2013/09/26 Javascript
javascript间隔定时器(延时定时器)学习 间隔调用和延时调用
2014/01/13 Javascript
JQuery做的一个简单的点灯游戏分享
2014/07/16 Javascript
jquery checkbox 勾选的bug问题解决方案与分析
2014/11/13 Javascript
javascript上下方向键控制表格行选中并高亮显示的方法
2015/02/13 Javascript
jQuery插件Slider Revolution实现响应动画滑动图片切换效果
2015/06/05 Javascript
javascript跨域的方法汇总
2015/10/23 Javascript
JS截取与分割字符串常用技巧总结
2015/11/10 Javascript
理解JavaScript表单的基础知识
2016/01/25 Javascript
深入理解jQuery3.0的domManip函数
2016/09/01 Javascript
简单理解vue中el、template、replace元素
2016/10/27 Javascript
微信小程序 网络请求(GET请求)详解
2016/11/16 Javascript
基于jQuery制作小图标上下滑动特效
2017/01/18 Javascript
JS实现从对象获取对象中单个键值的方法示例
2019/06/05 Javascript
layui 动态设置checbox 选中状态的例子
2019/09/02 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
2019/11/11 Javascript
python根据路径导入模块的方法
2014/09/30 Python
用python打印1~20的整数实例讲解
2019/07/01 Python
Pytorch基本变量类型FloatTensor与Variable用法
2020/01/08 Python
Python列表去重复项的N种方法(实例代码)
2020/05/12 Python
html5视频播放_动力节点Java学院整理
2017/07/13 HTML / CSS
爱普生美国官网:Epson美国
2018/11/05 全球购物
NYX Professional Makeup英国官网:美国平价专业彩妆品牌
2019/11/13 全球购物
《三亚落日》教学反思
2014/04/26 职场文书
大学应届毕业生求职信
2014/05/24 职场文书
宣传口号大全
2014/06/16 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
挂靠协议书
2015/01/27 职场文书
2016消防宣传标语口号
2015/12/26 职场文书
SpringCloud项目如何解决log4j2漏洞
2022/04/10 Java/Android