oop - 在 Go 中模仿适当的动态调度的惯用方法

标签 oop go dynamic-dispatch

我从 Java 转到 Go,有些事情让我感到困惑。

例如,让我们考虑以下代码:

package main

import (
    "fmt"
)

type I interface {
    Do()
    MegaDo()
}

type A struct {
}

func (a *A) Do() {
    fmt.Println("A")
}

func (a *A) MegaDo() {
    a.Do()
}

type B struct {
    A
}

func (a *B) Do() {
    fmt.Println("B")
}

var i I

func main() {
    fmt.Println("Hello, playground")

    var i I = &B{}

    i.MegaDo()
}

这里我们有一个接口(interface) I 和方法 Do()MegaDo() 。结构 A 在内部实现了方法和 MegaDo 调用 DoBA 组成,仅覆盖 Do()

如果我在 Java 中模仿相同的代码,我希望它打印“B”。但在 Go 中它打印“A”。

虽然我有点理解它为什么会发生(因为它是嵌入而不是继承),但我想知道如何在 Go 中模仿同样的事情。 例如,我有两个仅略有不同的相同接口(interface)的实现。在这种情况下如何最大限度地重用代码?我无法相信,为了在一个实现中自定义一些逻辑,我必须复制粘贴所有内容,并只修复我的代码中的一小部分。 也许在 Go 中有一些惯用的方法可以做到这一点?

最佳答案

Go 没有“类”的子类化或扩展。嵌入类型的方法使用它们的原始类型接收器。在这种情况下,方法 MegaDoB 中被提升,但在调用时,它是在 A 字段上调用的。 B.MegaDo() 只是 B.A.MegaDo() 的语法糖。因此,当它在其接收器上调用 Do() 时,它调用的是 A 版本,而不是 B 版本。

处理这个问题的更简单方法是嵌入一个接口(interface)。例如:

https://play.golang.org/p/ZPdK8zsy5_w

type Mega struct {
    I
}

func (m Mega) MegaDo() {
    m.Do()
} 

func main() {
    var a A
    var b B
    m := Mega{I: A}
    m.MegaDo()
    m.I = B
    m.MegaDo()
}

注意:在这种情况下实际上不需要嵌入接口(interface),因为 MegaDo() 可以简单地调用 m.i.Do() 如果它是一个命名字段。但是,嵌入它允许其他代码直接调用 m 上的 Do(),而不知道该字段中实际嵌入的是什么类型。另请注意,嵌入接口(interface)的实际结果是根据定义嵌入接口(interface)的结构也实现了相同的接口(interface)。

此模式的实际示例:嵌入 sql.DB 和 sql.Tx 类型(QueryRow、Query、Exec 等)的联合方法的数据库句柄类型。该句柄的用户可以调用这些方法,而不必知道它们是否在事务上下文中被调用。

关于oop - 在 Go 中模仿适当的动态调度的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49114057/

相关文章:

eclipse - 如何在安装了 goclipse 的 Eclipse 中运行 GO 项目

python - 引用纯虚方法

c# - 访问分配给传入 Func<> 参数的方法

c# - 当成员字段是对象的集合并且也是继承树的一部分时,成员字段中的多态性

对象的 Javascript oop 实例

java - 抽象方法与无实例方法?

go - 为什么分配给指针会导致 panic

Java监听器实现

oop - 戈朗 : Method expressions instances of Object

java - C中使用虚方法表的动态调度