2017-01-13 17 views
1

私は過去10年ほどJavaとPHPで使ってきたOOPスタイルのプログラミングを手放すことがどれほど難しいか気づきました。私はgolangに数週間から行っていますが、私はgolangが持っている継承原則よりも構図の周りに自然を感じようとしています。golangでインタフェースを定義するときの考え方は?

これらの構造体をすべて満たすためには、どのように便利なインターフェイスを定義すればよいですか?私はそれらの状態/データのまわりで私の考え方をベースにするので、それはかもしれないと思う

package main 

type Store struct { 
    name string 
    phone string 
} 

type HardwareStore struct{ Store } 

type FoodStore struct{ Store } 

type OnlineStore struct { 
    Store 
    url string 
} 

...犬、人間や車の奇妙な構造を伴わない有用な例を思い付くしようとしていませんでした彼らの行動、私は少し苦労しています。もちろん失敗

明白な最初の選択肢は、インターフェイスなしで、おそらくこの(簡体字)になり、:

s := Store{} 
h := HardwareStore{} 
f := FoodStore{} 
o := OnlineStore{} 

stores := []Store{s, h, f, o} 
+1

これはまだあなたが継承のようなものにしようとしているように聞こえますが、これはGoではうまくいきません。解決しようとしている具体的な問題がありますか? – JimB

+0

はい、ユーザーのタイプによって属性が異なるユーザーを囲みます。私は慣用的なやり方でそれを行うために継承から離れようとしています。 – Patrick

+3

継承ベースのOOPから離れるときに、ロジックを「反転」することができます。ユーザが異なる「タイプ」を持つのではなく、それらを区別する属性を持つユーザタイプを持っています。 _everything_の振る舞いを基にして、関心のあるフィールドを返すメソッドを定義し、メソッドセットを使ってインターフェースを定義することもできます。あなたが取り組んでいる問題に最もよく合うような人為的な例では言い難いです。 – JimB

答えて

1

私は以下のだと思うあなたは後にしているものです。醜い名前をつけて申し訳ありませんが、私はそれらを目立つようにしなければなりませんでした。そして、たとえその下の例がシミュレートされていても、仮想関数はありません。

package main 

import "fmt" 


type StoreInterface interface { 
    getName() string 
    setName(string) 
    getPhone() string 
    setPhone(string) 
} 

type Store struct { 
    name string 
    phone string 
} 

func (store *Store) getName() string { 
    return store.name; 
} 

func (store *Store) setName(newName string){ 
    store.name = newName; 
} 

func (store *Store) getPhone() string { 
    return store.phone; 
} 

func (store *Store) setPhone(newPhone string){ 
    store.phone = newPhone; 
} 

type HardwareStore struct{ Store } 

type FoodStore struct{ Store } 

type OnlineStore struct { 
    Store 
    url string 
} 

func (os *OnlineStore) getName() string{ 
    return fmt.Sprintf("%v(%v)", os.name, os.url) 
} 

func main() { 
    s := Store{name:"s", phone:"111"} 
    h := HardwareStore{Store{name:"h", phone:"222"}} 
    f := FoodStore{Store{name:"f", phone:"333"}} 
    o := OnlineStore{Store:Store{name:"o", phone:"444"}, url:"http://test.com"} 

    fmt.Println ("Printout 1") 
    stores := []*Store{&s, &h.Store, &f.Store, &o.Store} 
    for _, s := range stores { 
     fmt.Printf("\t%v: %v\n", s.name, s.phone); 
    } 

    fmt.Println ("Printout 2") 
    stores2 := []StoreInterface{&s, &h, &f, &o} 
    for _, s := range stores2 { 
     fmt.Printf("\t%v: %v\n", s.getName(), s.getPhone()); 
    } 
} 

また、想像を継承から機能、データ構造、動作に変更する必要があることは言うまでもありません。古い習慣を壊すのは難しい(私は何年ものOOPから来ている)。しかし、ローマではローマ人のように考えるべきです:そうでなければ、言語の潜在的可能性を見逃してしまいます。

+1

私は、慣用的な立場から正しいと感じなかったので、私のゴープログラミングでゲッターとセッターを定義することを避けましたが、とにかくそれが唯一の方法でしょうか? – Patrick

+0

アクセスのためだけのものであれば、なぜvarsに資本を書くのを公開しないのですか? – Michael

+1

@Patrick "Printout 2"の出力をチェックしましたか?それを「プリントアウト1」と比較しましたか?この例ではゲッターとセッターだけを使っていました。このコードは実際にOOPから継承と多型をシミュレートする方法を示しています。明らかに構造体フィールドにアクセスするためのインタフェースは必要ありません。それについては、「プリントアウト1」を参照してください。 – Seva

関連する問題