GO中的subclassing

很多时候我们希望写好一个框架,然后在实际运行的时候通过传入不同的对象来实现不同的效果(也就是动态绑定)。例如:

class Base(object):

    def run(self):
        # do something...
        self.XXX()
        # do somethin...

class X(Base):

    def XXX(self):
        # XXX

class Y(Base):

    def XXX(self):
        # YYY

此时X().run()和Y().run()就能在run()的大逻辑下,根据对象的不同实现X和Y的不同逻辑了。

下面看段GO的代码和Python的代码:

package main

import "fmt"

type Super struct{}

func (super *Super) name() string {
    return "Super"
}

func (super *Super) WhoAmI() {
    fmt.Printf("I'm %s.\n", super.name())
}

type Sub struct {
    Super
}

func (sub *Sub) name() string {
    return "Sub"
}

func main() {
    sub := &Sub{Super{}}
    sub.WhoAmI()
}

这段断码的输出为:

[root@dev tmp]# go run x.go
I'm Super.

再看这段代码:

class Super(object):

    def name(self):
        return "Super"

    def WhoAmI(self):
        print("I'm {name}".format(name=self.name()))

class Sub(Super):

    def name(self):
        return "Sub"


if __name__ == "__main__":
    sub  = Sub()
    sub.WhoAmI()

其输出为:

[root@dev tmp]# python x.py 
I'm Sub

为什么GO中的输出就不是sub而是super呢?如果此时我们要实现本文开头的run()的逻辑那在GO中不就歇菜了嘛…原因在于GO并没有子类的概念。下面的这个代码:

type Sub struct {
    Super
}

在GO中这段代码叫做嵌套(或者可以看成是组合)。当调用sub.WhoAmI()时,实际上调用的是sub.Super.WhoAmI(),此时的namespace属于Super,因此会输出Super。如果此时我们要实现本文开头的run()的逻辑应该咋办?

如果要实现Python的效果,代码要写成这样:

package main

import "fmt"

type Super struct{}
type Sub struct{ Super }

func (super *Super) name() string {
    return "Super"
}

func (sub *Sub) name() string {
    return "Sub"
}

type S interface {
    name() string
}

func WhoAmI(s S) {
    fmt.Printf("I'm %s.\n", s.name())
}

func main() {
    sub := &Sub{Super{}}
    WhoAmI(sub)
}

可以看到关键的地方就在于interface,通过interface实现了上面依靠子类继承实现的效果。那GO种为什么要舍弃子类而使用嵌套呢(其实GO或许并不是一门面向对象的语言)?小秦我能想到的就是以前在C语言中也是通过类似的方式(struct+函数指针+传一个self的指针)来实现类似GO中的这种代码,这种实现的好处是非常简单。那么有没有别的理由呢?或许http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition–which-one-should-you-choose-.html这篇文章里有一些答案。看上去这个是面向对象里的老问题了。在GO的语言层面,应该是组合优先,直接舍去了继承。相比较即支持组合又支持继承的语言(比如Java、Python、C++等等)要简单很多。

其实看下Python中的一些代码,很多继承都是走的mixin,真正的继承并没有太多的层次。另外很多时候都是通过stevedore等框架走组合来获取具体的实现方法的。从这一层面来讲,或许组合还是比较有优点的。

发表评论

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

*