web-dev-qa-db-ja.com

Golangと継承

「拡張」できるライブラリ内のメソッドを含む基本構造体を提供したいと思います。

この基本構造のメソッドは、拡張構造のメソッドに依存しています。構造メソッドは構造自体のフィールドにのみアクセスでき、親構造にはアクセスできないため、これはGoでは直接実行できません。

ポイントは、拡張する各クラスで繰り返す必要がない機能を持つことです。

私はこのパターンを考え出しましたが、これはうまく機能しますが、周期的な構造のため、かなり複雑に見えます。

他のGoコードでこのようなものを見つけたことはありません。これは非常に無事ですか?どのようなアプローチを取ることができますか?

type MyInterface interface {
  SomeMethod(string)
  OtherMethod(string)
}

type Base struct{
  B MyInterface
}

func (b *Base) SomeMethod(x string) {
  b.B.OtherMethod(x)
}

type Extender struct {
  Base
}

func (b *Extender) OtherMethod(x string) {
  // Do something...
}

func NewExtender() *Extender { 
  e := Extender{}
  e.Base.B = &e
  return &e
}
28
theduke

人々のコメントで述べたように、Goは継承よりも構成を奨励しています。

コードの重複を減らすことについての質問に対処するには、 embedding を使用します。

上記の Effective Go の例を使用すると、いくつかのことだけを行う非常に狭いインターフェースから始めます。

_type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}
_

次に、インターフェースを別のインターフェースにまとめることができます。

_// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}
_

構造体でも同様に機能し、ReaderとWriterを別の構造体で一緒に実装する構造体を作成できます。

_type MyReader struct {}
func (r *MyReader) Read(p []byte) (n int, err error) {
    // Implements Reader interface.
}
type MyWriter struct {}
func (w *MyWriter) Write(p []byte) (n int, err error) {
    // Implements Writer interface.
}

// MyReadWriter stores pointers to a MyReader and a MyWriter.
// It implements ReadWriter.
type MyReadWriter struct {
    *MyReader
    *MyWriter
}
_

基本的に、ReaderまたはWriterを実装するものはすべて、構造体で一緒に構成することで再利用でき、その外部構造体は自動的にReadWriterインターフェースを実装します。

これは基本的に Dependency Injection を実行しており、テストにも非常に役立ちます。

上記の構造コードの例:

_func (rw *MyReadWriter) DoCrazyStuff() {
    data := []byte{}
    // Do stuff...
    rw.Read(data)
    rw.Write(data)
    // You get the idea...
}

func main() {
    rw := &MyReadWriter{&MyReader{}, &MyWriter{}}
    rw.DoCrazyStuff()
}
_

他の言語の構成パラダイムと少し異なることを指摘する1つのことは、MyReadWriter構造体がReaderWriterの両方として機能できるようになったことです。 DoCrazyStuff()では、rw.Read(data)の代わりにrw.Reader.Read(data)を使用するのはそのためです。

更新:不適切な例を修正しました。

24
Addison

あなたを失望させて申し訳ありませんが、あなたは間違った質問をしています。 Goコードを書き始めたときも、同様の問題がありました。

クラス階層を単純にGoコードに変換することはできません。少なくとも満足のいく結果は得られません。通常、Goでそのようなことを解決するための非常にエレガントでシンプルな方法がありますが、それらを発見するには、慣れているように少し異なる考え方をする必要があります。

残念ながら、あなたの質問はあなたが解決しようとしているwhat問題について何も述べていません。 howについて説明しましたが、解決したいと考えています。したがって、慣用的なGoコードにつながらないため、一般的な答えを出すのには少し気が進まない。私はあなたがその答えに失望したかどうかを理解していますが、私の意見では、それはあなたが得ることができる最も価値のある答えです:)

7
tux21b