golang的继承实现

go的继承叫做“匿名组合”,这个不等同于组合,也就是说:“匿名组合”是“匿名组合”,“组合”是“组合”,两个完全不一样。下面看一个最简单的组合,然后再比较后面讲到的“匿名组合”,会发现两者不同。

type A struct {
}
func (a *A) Test() {
}

type B struct {
    a A
}
func (b *B) Test() {
    a.Test()
}

var b = new(B)
b.Test()

从上面可以看到“组合”的特点,要调用A的Test()方法,则需要用B的某个方法给封装一下,有没有一种更便利的方法,不用在B中写一个包装方法来调用,能不能省略掉B中的Test()包装方法呢?且看后面。

go的“匿名组合”,有三种实现形式:

1,匿名组合struct

type Human struct {
    Name string
}
func (a *Human) Test1() {}
type Student struct {
    Human
    Age int
}
func (a *Student) Test2() {}

var a = new(Student)
a.Name = "zhangsan"
a.Age = 11
a.Test2()
a.Test1() == a.Human.Test1()  //这2种方式都可以

2,匿名组合指向struct的指针

type Hobby struct {
    Name string
}
func (a *Hobby) Test1() {}

type Student struct {
    *Hobby
    Age int
}

var h = &Hobby{"movie"}
var s = &Student{h,18}
s.Test1()

初看这种方式和第一种匿名组合struct没有什么区别,而且更麻烦了,在创建Student的时候,还要对其中的*Hobby进行赋值。但是细细一想,这种模式的优点很大,这种类型的“匿名组合”实际上是第一种的“匿名组合”stuct再加上”组合“这2种模式而成。

对于第一种”匿名组合“struct,往往用在派生类和父类有一定继承关系上,而对于第二种的”匿名组合“指向struct的指针来说,派生类中的组合对象可以和父类没有太大的关系或者没有任何关系,就是一个纯粹的”组合“模式,上面讲到了,在组合模式中要调用父类的方法,需要在派生类中再写一个包装方法,很是麻烦。刚好,用第二种的”匿名组合“指向struct的指针这种模式来说,非常好的解决了这个问题,非常完美。

上面的例子假如看得还不是特别明白的话,好好体会下面这个例子就非常清楚了,这个模式非常不错:

package main

import (
    "fmt"
    "log"
    "os"
)

type MyJob struct {
    Command string
    *log.Logger
}

func (job *MyJob) Start() {
    job.Println("job started!") // job.Logger.Println

    fmt.Println(job.Command)

    job.Println("job finished!") // job.Logger.Println
}

func main() {
    logFile, err := os.OpenFile("./job.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0)
    if err != nil {
        fmt.Println("%s", err.Error())
        return
    }
    defer logFile.Close()

    logger := log.New(logFile, "[info]", log.Ldate|log.Ltime|log.Llongfile)
    job := MyJob{"programming", logger}

    job.Start()
    job.Println("test finished!") // job.Logger.Println
}

因为 MyJob 内组合的*log.Logger和MyJob关系不是纯粹的继承,假如将 log.Logger 采用组合的方式,那么还需要对 MyJob 再定义一个 Println 或者一系列方法,而采用”匿名组合“指向struct指针的这种方法就有效的解决了这些问题,细细体会。

3,匿名组合接口

这个和第2种模式几乎一样,也需要在实例化派生类的时候,要对其中的匿名组合进行接口实现类的赋值,道理和第2种一样。

发表评论

邮箱地址不会被公开。 必填项已用*标注