2014-01-21 37 views
32

BはAから継承し、AのFoo()メソッドをオーバーライドするだけですが、B.Foo()を印刷するコードが欲しいですが、A.Foo()はまだ印刷されています。動的なバインディングが有効になっているとき、コードは私が望むように動作することができるC++で、Golangの受信機はこのように動作しません。golangの親構造体からオーバーライドされたメソッドを呼び出すことは可能ですか?

私はまた動作するコードをもう1つ掲載しますが、実装するのが難しく、ハックのようなものですが、ゴランスタイルではないと思います。

私の問題は、親のBar()メソッドにいくつかのロジックがある場合(たとえば、ファイルを開き、いくつかの行を読み込み、Foo()を使ってこれらの行をstdoutに出力し、Child例B)はそれらの大部分を使用したいが、唯一の違いは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() 

答えて

12

あなたが書いたように遭遇したときに、どのような移動が持つことは本当に継承ではないことフィーチャのような継承を可能にすることを埋め込みと呼びます。それが埋め込まれた構造体は、それが埋め込まれていることは考えていないということですので、あなたがそれから呼び出されたものを上書きすることはできません基本的に意味は何

http://golang.org/doc/effective_go.html#embedding

。あなたは実際に埋め込み構造体を取って、埋め込み構造体からの参照だけを取ることができます。

これを行うための最善の方法は、インターフェイスを使用した何らかの依存性注入を使用して、多かれ少なかれ2番目の例に似ています。すなわち、Aは、実際の作業を行うインタフェース、例えばworkerを参照して、ファイルに書き込むか何かを行う。そして、Bをインスタンス化するときに、Aのworkerを別のワーカーに置き換えます(もちろんAを埋め込むことなく)。 AはちょうどmyWorker.Work()のようなことをしています。

+0

、第二の例では、Iは、AとBの両方の複合インタフェース、達成するために組成物を使用し、これはencounragesをgolangものです。 – zhaozhi

+0

ええ、私はあなたの2番目の例を書いているので、行く方法です。私は親構造体が独自のインタフェースではないように変更しています。 –

+0

Not_a_Golfer、 "親構造体は独自のインタフェースではない"ということはどういう意味ですか - コード内でどのように見えますか、何を示唆していますか? :-) – Dac0d3r

2
package main 

import (
    "fmt" 
) 


//-- polymorphism in work 

// children specification by methods signatures 
// you should define overridable methods here 
type AChildInterface interface { 
    Foo() 
} 

type A struct { 
    child AChildInterface 
} 

//-- /polymorphism in work 


// hard A.Bar method 
func (a *A) Bar() { 
    a.child.Foo() // Foo() will be overwritten = implemented in a specified child 
} 


//-- default implementations of changeable methods 

type ADefaults struct{} 

func (ad ADefaults) Foo() { 
    fmt.Println("A.Foo()") 
} 

//-- /default 


//-- specified child 

type B struct { 
    ADefaults // implement default A methods from ADefaults, not necessary in this example 
} 

// overwrite specified method 
func (b B) Foo() { 
    fmt.Println("B.Foo()") 
} 

//-- /specified child 

func main() { 
    a := A{ADefaults{}} 
    a.Bar() 

    // Golang-style inheritance = embedding child 
    b := A{B{}} // note: we created __Parent__ with specified __Child__ to change behavior 
    b.Bar() 
} 

出力:

A.Foo() 
B.Foo() 
2

最近、私はこれを行う必要があり、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()) 
} 
関連する問題