Go继承的方法重写,继承抽象类实现

go的接口和继承就没什么好说的了,基本上大家都知道怎么玩,这里说下可能会困扰大家的问题。在Java里方法的重写和抽象类是很好用的,对于抽象和尽量共用抽象出来的代码很重要,但是用go很多人又不知道该怎么写才好,所以这里说下在go里怎么实现

方法重写

func main() {
	m := &Man{}
	m.Eat()
	m.Run()
	m.Sleep()
}

type Person struct {
}

func (this *Person) Eat() {
	fmt.Println("Person Eat")
}

func (this *Person) Run() {
	fmt.Println("Person Run")
}

func (this *Person) Sleep() {
	fmt.Println("Person Sleep")
}

type Man struct {
	Person
}

func (this *Man) Eat() {
	// 类似于Java的 super.Eat()
	this.Person.Eat()
	fmt.Println("Man Eat")
}

func (this *Man) Run() {
	fmt.Println("Man Run")
}

运行结果:

Person Eat
Man Eat
Man Run
Person Sleep

这里重写了Eat方法,但是里面通过显示调用父类的Eat方法模拟出Java的super.xxx的效果,所以先打印Person eat,然后打印Man Eat

然后重写了Run方法,所以覆盖掉了父类的Run方法,打印出Man Run

最后因为Man没有实现Sleep方法,所以调用Man的Sleep方法其实是调用的父类Person的实现,打印出Person Sleep

抽象类

抽象类困扰了我很长时间,后来在c语言的很多项目里面找到了答案,那就是使用函数指针

func main() {
	akita := NewAkita()
	akita.Eat()

	labrador := NewLabrador()
	labrador.Eat()
}

type AbstractDog struct {
	Sleep func()
}

func (this *AbstractDog) Eat() {
	fmt.Println("AbstractDog Eat")
	this.Sleep()
}

func (this *AbstractDog) Run() {
	fmt.Println("AbstractDog Run")
}

// 秋田犬
type Akita struct {
	AbstractDog
}

func NewAkita() *Akita {
	ptr := &Akita{}
	ptr.AbstractDog.Sleep = ptr.Sleep
	return ptr
}

func (this *Akita) Sleep() {
	fmt.Println("Akita Sleep")
}

// 拉布拉多犬
type Labrador struct {
	AbstractDog
}

func NewLabrador() *Labrador {
	ptr := &Labrador{}
	ptr.AbstractDog.Sleep = ptr.Sleep
	return ptr
}

func (this *Labrador) Sleep() {
	fmt.Println("Labrador Sleep")
}

运行结果:

AbstractDog Eat
Akita Sleep
AbstractDog Eat
Labrador Sleep

这里关键的意思是秋田和拉布拉多共享了eat方法的实现,也许eat方法里有共同的逻辑而且代码有几百行,但是eat方法里又调用了不同的狗的实现的sleep方法,最终抽象出了共同的部分,又派生了不同的实现,模仿了Java的抽象类