封装 继承 多态_Go的接口、继承及OOP中的封装、继承、多态

本文探讨了Go语言中的面向对象编程(OOP)特性,包括封装、继承和多态,并对比了Go与Java在OOP支持方面的差异。Go通过组合而非传统继承实现类之间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

74e47b20251065fe459ec04f81424b4f.png

一、前言

OOP特性有三:封装、继承、多态。

封装:通过权限控制保证数据安全,隐藏细节(直接api调用就行),提供简单的接口。

继承:继承可以复用代码内容,例如多个类的同一个方法对外表现都是一样的,那么可以抽取到父类中。而接口定义了一套规范,所有实现接口的类必须遵守这个规范,具有相同的能力。能力表现可能不尽相同。

多态:多态分为静态多态和动态多态。静态多态:方法重载。动态多态:通过上述的继承实现。

这三大特性,保证了我们可以非常高效的利用代码,同时对使用代码的程序员也是非常的友好!

二、Go的接口和继承

写过Java的都知道,Java对封装、继承、多态支持的非常友好。但是Go语言中接口支持尚可,但是继承和抽象类能力非常拉胯。

Go是通过组合来实现继承的,你没有看错,就是UML的组合,即子类持有父类对象的实例当做继承(这算哪门子继承?),代码如下:

package main

import "fmt"

/**
声明人类这个接口,有吃饭“eat”的方法
*/
type computer struct {
	logo string
	// 不能在结构体中声明方法
	// ShowLogo()
}

//如果一个struct嵌入另一个匿名结构体,就可以直接访问匿名结构体的字段或方法,从而实现继承
type dell struct {
	// 匿名结构体
	computer
}

//如果一个struct嵌套了另外一个有名结构体,是UML中的组合或者聚合(根据实际情况来定)
type apple struct{
	pc computer
}




/**
声明了父类computer的showLogo方法,接收computer做对象
 */
func (ptr computer) ShowLogo(){
	fmt.Println("当前电脑的logo是:" + ptr.logo)
}

func main() {
	// 因为go只有伪继承, 其本质是一种语法糖, 无法实现继承中动态绑定等特性. 且构造函数, 连伪继承都达不到.所以一下代码编译会报错类型不匹配 Cannot use 'dell{computer{logo: "dell"}}' (type dell) as type computer
	//var pc computer = dell{computer{logo: "dell"}}
	//showLogo(pc)
	//pc = apple{computer{logo: "apple"}}
	//showLogo(pc)

	// 伪继承可以直接调用,但是不能使用父类指针指向子类对象
	var d dell = dell{computer{logo: "dell"}}
	d.ShowLogo()
	// 组合更不能了。
	var a apple = apple{computer{logo: "apple"}}
	a.pc.ShowLogo()
}

func showLogo(pc computer){
	pc.ShowLogo()
}

继承拉胯的难受,但是还好Go语言有提供interface:

package main

import "fmt"

/**
声明人类这个接口,有吃饭“eat”的方法
*/
type animal interface {
	// 接口内不能声明字段
	//name string

	// 说方法,这里string是返回值的意思,实现类的方法签名和接口一致。
	Say() string
	// 走路方法,没有返回值
	Walk()
}

type human struct {
	// 做事的内容
	walkWay string
	// 说话的内容
	sayContent string
}

/**
下面的实现方法中,一个使用human一个使用 * human来接收对象。
只要使用了指针对象,在创建对象时必须使用&来获得对象的引用
*/
// 这里是 (human)类型,所以函数内部不可以对当前对象进行更改,只能读取内容
func (instance human) Say() string {
	fmt.Println("人类说:" + instance.sayContent)
	return instance.sayContent
}

// 这里是 (* human)类型,所以函数内部可以对当前对象进行更改
func (instance *human) Walk() {
	fmt.Println("人类走路:" + instance.walkWay)
}

type dog struct {
	// 做事的内容
	walkWay string
	// 说话的内容
	sayContent string
}

// 这里是 (human)类型,所以函数内部不可以对当前对象进行更改,只能读取内容
func (instance dog) Say() string {
	fmt.Println("狗说:" + instance.sayContent)
	return instance.sayContent
}

// 这里是 (* human)类型,所以函数内部可以对当前对象进行更改
func (instance *dog) Walk() {
	fmt.Println("狗走路:" + instance.walkWay)
}


func main() {
	var a animal = &human{"人走路", "我是一个人"}
	doWalk(a)
	doSay(a)
	a = &dog{"狗走路", "汪汪汪"}
	doWalk(a)
	doSay(a)
}

// 多态
// 模拟业务操作,然后调用到say方法
func doSay(a animal) {
	// do sth
	a.Say()
}

// 模拟业务操作,然后调用到walk方法
func doWalk(a animal) {
	// do sth 模拟具体的业务操作,
	a.Walk()
}

go的接口代码和java的区别不大,但是go的接口中无法声明字段。可以使用接口实现多态。实际使用应该和java差不多。

看到接口你一定会想到抽象类,百度了一下发现Go没有抽象类的概念,抽象类也只能自己伪装一个抽象类:

package main

import "fmt"

// 游戏接口
type IGame interface {
	Name() string
}


// 抽象的游戏,实际并不抽象(假抽象)
type AbstractGame struct{}

func (g *AbstractGame) play(game IGame) {
	fmt.Println(fmt.Sprintf("%s is awesome!", game.Name()))
}

// Dota游戏,嵌入匿名结构体的方式继承抽象类
type Dota struct {
	AbstractGame
}

func (d *Dota) Name() string {
	return "Dota"
}

// Lol游戏,嵌入匿名结构体的方式继承抽象类
type LOL struct {
	AbstractGame
}

func (l *LOL) Name() string {
	return "LOL"
}
func main() {
	dota := &Dota{}
	dota.play(dota)
	lol := &LOL{}
	lol.play(lol)
}

抽象类是通过接口 + 伪继承实现的,哈哈哈哈!

三、总结

Go语言的OOP支持做的比较差,或者说Go语言的继承做的比较差,或者说Go认为继承是不必要的。

比起Go语言,Java需要花更多更长的时间才能了解Java的内容,但是也正因为如此抽象能力也非常强,非常适合做大型的项目。而Go相对java在抽象能力表达能力等会差一点,但是上手非常快,所以相对来说可能更适合中小型项目。

当然这并不绝对,比如加拿大某知名网站(数十亿用户)用的是PHP,而go大型项目应用主要用bilibili和youtube等。

工具的好坏看用在谁的手上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值