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

标签 oop inheritance go composition

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

如果是,有没有语言层面的解决方案?

最佳答案

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

fragile base class问题通常归咎于 virtual methods (方法的动态分配 – 这意味着如果方法可以被覆盖,则在这种被覆盖的方法的情况下必须调用的实际实现只能在运行时决定)。

为什么这是个问题?你有一个类,你向它添加了一些方法,如果 MethodA() 调用 MethodB(),你不能保证 MethodB( ) 您编写的将被调用,而不是覆盖您的 MethodB() 的子类的其他一些方法。

在 Go 中有 embedding , 但没有 polymorphism .如果将类型嵌入到结构中,则嵌入类型的所有方法都会提升 并将位于 method set 中包装器结构类型。但是您不能“覆盖”提升的方法。当然,您可以添加自己的同名方法,并在包装​​器结构上调用该名称的方法将调用您的方法,但如果从嵌入式类型调用此方法,则不会将其分派(dispatch)给您的方法,它仍将调用为嵌入类型定义的“原始”方法。

因此,我认为脆弱的基类问题仅以相当缓和的形式存在于 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

现在让我们按照在 Java 示例中所做的相同方式更改 Counter.Inc():

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 值的引用。

关于oop - Go 中是否存在脆弱的基类问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41819033/

相关文章:

java - 扩展对象隐式

go - 如何通过另一个值的 reflect.Type 在 Golang 中转换值类型

c++ - 在定义自定义接口(interface)时继承库类

c# - 构造函数 + 依赖注入(inject)

javascript - 用JavaScript封装,存在吗?

go - 使用接口(interface)设置具体结构的值

go - Bazel 在处理 protobuf 文件时有一个错误。我怎样才能暂时解决这个问题?

java - 如何访问需要一些信息的非静态方法?

ruby - 如何找到super执行的代码的source_location?

inheritance - 为什么重载的成员函数只有在 D 中没有被覆盖的情况下才会自动继承?