我想实现这样的代码,其中B继承自A并且只覆盖A的Foo()方法,我希望代码打印B.Foo(),但它仍然打印A.Foo(),似乎接收器在Golang在C ++中无法像这样工作,在启用动态绑定的情况下,代码可以像我想要的那样工作。
我还发布了另一段代码,但它实现起来太难了,而且更像是一种黑客方式,我认为它不是Golang风格。
所以我的问题是:如果父的Bar()方法有一些逻辑,例如,打开一个文件,然后读取一些行,并使用Foo()将这些行输出到stdout
,并将Child(在示例中为B)想要使用它们中的大多数,唯一的区别是Child希望Foo()将行输出到另一个文件。我该如何实施呢?我听说Golang的继承不能像C ++或Java那样工作,Golang中的正确方法是什么?
package main
import (
"fmt"
)
type A struct {
}
func (a *A) Foo() {
fmt.Println("A.Foo()")
}
func (a *A) Bar() {
a.Foo()
}
type B struct {
A
}
func (b *B) Foo() {
fmt.Println("B.Foo()")
}
func main() {
b := B{A: A{}}
b.Bar()
}
output: A.Foo()
以下作品有效,但写作时
a := A{}
a.Bar()
您将遇到编译器错误
package main
import (
"fmt"
)
type I interface {
Foo()
}
type A struct {
i I
}
func (a *A) Foo() {
fmt.Println("A.Foo()")
}
func (a *A) Bar() {
a.i.Foo()
}
type B struct {
A
}
func (b *B) Foo() {
fmt.Println("B.Foo()")
}
func main() {
b := B{A: A{}}
b.i = &b // here i works like an attribute of b
b.Bar()
output: B.Foo()
最近我需要这样做,OP提出的组合方法很有用。
我尝试创建另一个示例来尝试演示父子关系并使其更易于阅读。
https://play.golang.org/p/9EmWhpyjHf:
package main
import (
"fmt"
"log"
)
type FruitType interface {
Wash() FruitType
Eat() string
}
type Fruit struct {
name string
dirty bool
fruit FruitType
}
func (f *Fruit) Wash() FruitType {
f.dirty = false
if f.fruit != nil {
return f.fruit
}
return f
}
func (f *Fruit) Eat() string {
if f.dirty {
return fmt.Sprintf("The %s is dirty, wash it first!", f.name)
}
return fmt.Sprintf("%s is so delicious!", f.name)
}
type Orange struct {
*Fruit
}
func NewOrange() *Orange {
ft := &Orange{&Fruit{"Orange", true, nil}}
ft.fruit = ft
return ft
}
func NewApple() *Fruit {
ft := &Fruit{"apple", true, nil}
return ft
}
func (o *Orange) Eat() string {
return "The orange is so sour!"
}
func main() {
log.Println(NewApple().Eat())
log.Println(NewApple().Wash().Eat())
log.Println(NewOrange().Eat())
log.Println(NewOrange().Wash().Eat())
}
我自己也在苦苦挣扎。找到2个解决方案
package main
import "fmt"
type ABCD interface {
Foo()
}
type A struct {
}
func (a *A) Foo() {
fmt.Println("A.Foo()")
}
type B struct {
A
}
func (b *B) Foo() {
fmt.Println("B.Foo()")
}
// Bar is common "method", as external function.
func Bar(a ABCD) {
a.Foo()
}
func main() {
b := &B{} // note it is a pointer
// also there's no need to specify values for default-initialized fields.
Bar(b) // prints: B.Foo()
}
在Go Playground尝试:https://play.golang.org/p/FF4fdvTCRAo
package main
import "fmt"
//////////////////////////////////////////////////////////////////////
// Implementation.
// aBase is common "ancestor" for A and B.
type aBase struct {
ABCD // embed the interface. As it is just a pointer, it has to be initialized!
}
// Bar is common to A and B.
func (a *aBase) Bar() {
a.Foo() // aBase has no method Foo defined, so it calls Foo method of embedded interface.
}
// a class, not exported
type a struct {
aBase
}
func (a *a) Foo() {
fmt.Println("A.Foo()")
}
// b class, not exported
type b struct {
aBase
}
func (b *b) Foo() {
fmt.Println("B.Foo()")
}
//////////////////////////////////////////////////////////////////////
// Now, public functions and methods.
// ABCD describes all exported methods of A and B.
type ABCD interface {
Foo()
Bar()
}
// NewA returns new struct a
func NewA() ABCD {
a := &a{}
a.ABCD = a
return a
}
// NewB returns new struct b
func NewB() ABCD {
b := &b{}
b.ABCD = b
return b
}
func main() {
b := NewB()
b.Bar() // prints: B.Foo()
a := NewA()
a.Bar() // prints: A.Foo()
}
在Go Playground尝试:https://play.golang.org/p/0Zcs_arturP
Go不支持虚方法覆盖。因此,Go不直接支持您要使用的设计模式。这被认为是不好的做法,因为更改A.Bar()的实现会破坏所有派生类,如B,假设A.Boo()将调用A.Foo()。您要使用的设计模式将使您的代码变得脆弱。
在Go中执行此操作的方法是使用Foo()方法定义Fooer接口。 Fooer将作为参数传递给Bar()或存储在A的字段中并由A.Bar()调用。要更改Foo操作,请更改Fooer值。这称为组合,它比通过继承和方法重写更改Foo操作要好得多。
这是在Go:https://play.golang.org/p/jJqXqmNUEHn做你想做的事的惯用方法。在此实现中,Fooer是A的成员字段,其由实例工厂函数NewA()
的参数初始化。当Fooer在A的生命周期中不经常更改时,此设计模式是首选。否则,您可以将Fooer作为Bar()
方法的参数传递。
这就是我们改变Go中Foo()
行为的方式。它被称为组合,因为您通过更改组成A的实例来更改Bar()
的行为。
package main
import (
"fmt"
)
type Fooer interface {
Foo()
}
type A struct {
f Fooer
}
func (a *A) Bar() {
a.f.Foo()
}
func NewA(f Fooer) *A {
return &A{f: f}
}
type B struct {
}
func (b *B) Foo() {
fmt.Println("B.Foo()")
}
type C struct {
}
func (c *C) Foo() {
fmt.Println("C.Foo()")
}
func main() {
a := NewA(new(B))
a.Bar()
a.f = &C{}
a.Bar()
}
PS:以下是您希望为文档目的实现的设计模式的可能实现:https://play.golang.org/p/HugjIbYbout