inheritance - language - Golang y herencia
golang inheritance (2)
Quiero proporcionar una estructura base con métodos en mi biblioteca que puedan ser ''ampliados''.
Los métodos de esta estructura base se basan en métodos de la estructura extendida. Esto no es directamente posible en Go, porque los métodos de estructura solo tienen acceso a los campos propios de la estructura, no a las estructuras principales
El punto es tener una funcionalidad que no tengo que repetir en cada clase extendida.
He creado este patrón, que funciona bien, pero se ve bastante complicado debido a su estructura cíclica.
Nunca he encontrado nada igual en otro código de Go. ¿Esto es muy irresistible? ¿Qué enfoque diferente podría tomar?
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
}
Como se menciona en los comentarios de la gente, Go fomenta la composición sobre la herencia.
Para responder a su pregunta sobre la reducción de la duplicación de código, desearía utilizar la embedding .
Usando el ejemplo de embedding vinculado anteriormente, comienza con interfaces muy estrechas que solo hacen algunas cosas:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
A continuación, puede componer interfaces en otra interfaz:
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
Funciona de manera similar para las estructuras, donde puede componer estructuras que implementan Reader y Writer juntas en otra estructura:
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
}
Básicamente, cualquier cosa que implemente un Reader
o un Writer
puede reutilizarse al componerlos juntos en una estructura, y esa estructura externa implementará automáticamente la interfaz de ReaderWriter
.
Básicamente, esto es hacer inyección de dependencia , y también es muy útil para realizar pruebas.
Ejemplo del código de la estructura anterior:
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()
}
Una cosa para señalar que es ligeramente diferente del paradigma de composición de otros idiomas es que la estructura MyReadWriter
ahora puede actuar como un Reader
y un Writer
. Es por eso que en DoCrazyStuff()
hacemos rw.Read(data)
lugar de rw.Reader.Read(data)
.
ACTUALIZACIÓN: Se corrigió el ejemplo incorrecto.
Lamento decepcionarte, pero estás haciendo la pregunta incorrecta. Tuve un problema similar cuando comencé a escribir código Go.
No puede simplemente tomar una jerarquía de clases y traducirla a código Go, al menos no con resultados satisfactorios. Por lo general, hay una manera muy elegante y sencilla de resolver este tipo de problemas en Go, pero para descubrirlos, debes pensar de forma un poco diferente a como estás acostumbrado.
Desafortunadamente, su pregunta no dice nada sobre qué problema está tratando de resolver. Acabas de describir cómo te gustaría resolverlo. Por lo tanto, me resisto un poco a dar una respuesta general, ya que no conducirá a un código Go idiomático. Entiendo que estás decepcionado por esa respuesta, pero en mi opinión, esa es la respuesta más valiosa que puedes obtener :)