Go中是否存在脆弱的基类问题?

时间:2017-01-24 02:28:00

标签: oop inheritance go composition

尽管使用组合而不是继承?

如果是这样,在语言层面是否有任何解决方案?

2 个答案:

答案 0 :(得分:8)

正如VonC所写,但我想指出一些事情。

fragile base class问题通常归咎于virtual methods动态调度方法 - 这意味着如果方法可以被覆盖,那么必须调用的实际实现这种被覆盖的方法只能在运行时决定。

为什么这是一个问题?你有一个类,你添加了一些方法,如果MethodA()调用MethodB(),你就不能保证你所调用的MethodB()会被调用而不是其他方法覆盖MethodB()

的子类

在Go中有embedding,但没有polymorphism。如果在结构中嵌入类型,则嵌入类型的所有方法都将提升,并且将位于包装器结构类型的method set中。但是你无法“覆盖”推广的方法。当然,您可以使用相同的名称添加自己的方法,并在包装​​器结构上调用该名称的方法将调用您的方法,但是如果从嵌入类型调用此方法,则不会将该方法调度到您的方法,仍将调用已定义为嵌入类型的“原始”方法。

因此,我认为脆弱的基类问题只在Go中以一种相当缓和的形式存在。

实施例

在Java中展示问题

我们来看一个例子。首先是Java,因为Java“遭受”这种问题。让我们创建一个简单的Counter类和一个MyCounter子类:

class Counter {
    int value;

    void inc() {
        value++;
    }

    void incBy(int n) {
        value += n;
    }
}

class MyCounter extends Counter {
    void inc() {
        incBy(1);
    }
}

实例化并使用MyCounter

MyCounter m = new MyCounter();
m.inc();
System.out.println(m.value);
m.incBy(2);
System.out.println(m.value);

输出符合预期:

1
3

到目前为止一切顺利。现在,如果基类Counter.incBy()将更改为:

void incBy(int n) {
    for (; n > 0; n--) {
        inc();
    }
}

基类Counter仍然完美且可操作。但MyCounter出现故障:MyCounter.inc()调用Counter.incBy(),调用inc(),但由于动态调度,它会调用MyCounter.inc() ...是的...无尽的循环。堆栈溢出错误。

在Go

中演示缺少问题

现在让我们看一下相同的例子,这次是用Go:

写的
type Counter struct {
    value int
}

func (c *Counter) Inc() {
    c.value++
}

func (c *Counter) IncBy(n int) {
    c.value += n
}

type MyCounter struct {
    Counter
}

func (m *MyCounter) Inc() {
    m.IncBy(1)
}

测试它:

m := &MyCounter{}
m.Inc()
fmt.Println(m.value)
m.IncBy(2)
fmt.Println(m.value)

输出符合预期(在Go Playground上尝试):

1
3

现在让我们改变Counter.Inc(),就像我们在Java示例中所做的那样:

func (c *Counter) IncBy(n int) {
    for ; n > 0; n-- {
        c.Inc()
    }
}

运行完美,输出相同。在Go Playground上尝试。

这里发生的事情是MyCounter.Inc()会调用Counter.IncBy()来调用Inc(),但Inc()Counter.Inc(),所以这里没有无限循环。 Counter甚至不知道MyCounter,它没有任何对嵌入式MyCounter值的引用。

答案 1 :(得分:2)

Fragile base class问题是,当派生类继承对基类进行看似安全的修改时,可能会导致派生类出现故障。

如上所述in this tutorial

  

对于所有意图和目的,e mbedding an anonymous type的组合等同于实现继承。嵌入式结构与基类一样脆弱。