web-dev-qa-db-fra.com

Golang et héritage

Je veux fournir une structure de base avec des méthodes dans ma bibliothèque qui peuvent être "étendues".

Les méthodes de cette structure de base reposent sur des méthodes de la structure d'extension. Ce n'est pas directement possible dans Go, car les méthodes de struct n'ont accès qu'aux propres champs de struct, pas aux structures parentes.

Le but est d'avoir des fonctionnalités que je n'ai pas à répéter dans chaque classe d'extension.

J'ai trouvé ce modèle, qui fonctionne bien, mais semble assez alambiqué en raison de sa structure cyclique.

Je n'ai jamais rien trouvé de tel dans un autre code Go. Est-ce que ça ne marche pas? Quelle approche différente pourrais-je adopter?

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

Comme mentionné dans les commentaires des gens, Go encourage la composition plutôt que l'héritage.

Pour répondre à votre question sur la réduction de la duplication de code, vous souhaitez utiliser incorporation .

En utilisant l'exemple de Effective Go lié ci-dessus, vous commencez avec des interfaces très étroites qui ne font que quelques choses:

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

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

Ensuite, vous pouvez soit composer des interfaces ensemble dans une autre interface:

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

Cela fonctionne de la même manière pour les structures, où vous pouvez composer des structures qui implémentent Reader et Writer ensemble dans une autre structure:

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
}

Fondamentalement, tout ce qui implémente un Reader ou un Writer peut être réutilisé en les composant ensemble dans une structure, et cette structure externe implémentera automatiquement l'interface ReadWriter.

Cela fait essentiellement injection de dépendance , et c'est aussi très utile pour les tests.

Exemple du code struct ci-dessus:

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()
}

Une chose à souligner qui est légèrement différente du paradigme de composition des autres langages est que la structure MyReadWriter peut maintenant agir à la fois comme Reader et Writer. C'est pourquoi dans DoCrazyStuff() nous faisons rw.Read(data) au lieu de rw.Reader.Read(data).

MISE À JOUR: Correction d'un exemple incorrect.

24
Addison

Désolé de vous décevoir, mais vous posez la mauvaise question. J'ai eu un problème similaire lorsque j'ai commencé à écrire du code Go.

Vous ne pouvez pas simplement prendre une hiérarchie de classes et la traduire en code Go, du moins pas avec des résultats satisfaisants. Habituellement, il existe un moyen très élégant et simple de résoudre de telles choses dans Go, mais pour les découvrir, vous devez penser un peu différemment comme vous en avez l'habitude.

Malheureusement, votre question ne dit rien sur le problème quoi que vous essayez de résoudre. Vous venez de décrire comment vous souhaitez le résoudre. Par conséquent, je suis un peu réticent à donner une réponse générale, car cela ne conduira pas à un code Go idiomatique. Je comprends si vous êtes déçu par cette réponse, mais à mon avis, c'est la réponse la plus valable que vous puissiez obtenir :)

7
tux21b