Joh*_*ray 0 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()
}
Run Code Online (Sandbox Code Playgroud)
这里我们有一个I方法Do()和接口MegaDo()。Struct A既实现方法又实现内部MegaDo调用Do。而B由以上A,仅覆盖Do()
如果我要模仿Java中的相同代码,我希望它显示“ B”。但是在Go中,它会打印“ A”。
虽然我有点理解为什么会发生(因为它是嵌入的而不是继承的),但我想知道如何在Go中模仿相同的东西。例如,我有两个相同接口的实现,只是略有不同。在这种情况下,如何最大程度地重用代码?我不敢相信,为了在一个实现中自定义位逻辑,我必须复制粘贴所有内容并只修复我的代码中的一小部分。也许在Go中有一些惯用的方法可以做到这一点?
您的问题过于抽象,无法很好地回答,但我希望这会有所帮助。
从您要解决的实际问题(业务需求等)开始重新考虑设计,不要在使用Java设计的Go中解决它。Go没有继承,接口是其唯一的多态形式。您不能以任何合理的方式在Go中“模拟动态调度”。
具体而言,在此方面:
我有两个相同接口的实现,只是略有不同。在这种情况下,如何最大程度地重用代码?我不敢相信,为了在一个实现中自定义位逻辑,我必须复制粘贴所有内容并只修复我的代码中的一小部分。
重新考虑代码重用而不是类层次结构,因为没有设计。如果您具有同一接口的两个实现,那很好!Go有接口,它们工作得很好。如果您在两个实现中都重复了一堆代码,或者a)将共享代码抽象为两个实现都可以调用的函数,或者b)如果差异确实很小,也许它应该是具有一些简单切换逻辑的单个实现。
Go没有“类”的子类或扩展名。嵌入式类型的方法使用其原始类型的接收器。在这种情况下,该方法MegaDo在内提升B,但在调用时在A现场调用。 B.MegaDo()只是语法糖B.A.MegaDo()。因此,当它调用Do()接收者时,它正在调用A版本,而不是B版本。
处理此问题的更简单方法是嵌入接口。例如:
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()
}
Run Code Online (Sandbox Code Playgroud)
注意:在这种情况下,实际上不需要嵌入接口,如果它是一个命名字段,则MegaDo()可以简单地调用m.i.Do()它。然而,嵌入它允许其他代码直接调用Do()的m,不知道是什么类型实际上是嵌入在现场。还应注意,嵌入接口的实际结果是,根据定义嵌入接口的结构也可以实现相同的接口。
此模式的实际示例:嵌入sql.DB和sql.Tx类型(QueryRow,Query,Exec等)的联合方法的DB处理类型。该句柄的用户可以调用那些方法,而不必知道它们是否在事务上下文中被调用。
| 归档时间: |
|
| 查看次数: |
1050 次 |
| 最近记录: |