¿Cómo puede un paquete externo implementar una interfaz de forma implícita?
Estoy escribiendo un fragmento de código que depende de alguna implementación.
Quiero desacoplar la implementación de mi código y hacer que sea lo más independiente posible.
Pensé en lograr este enfoque utilizando interfaces en lugar de tipos concretos, de la siguiente manera:
package mypackage
type MyType interface {
Title() string
Price() int
}
type TypeGetter interface {
GetType() MyType
}
func MyHandler(tg TypeGetter) {
t := tg.GetType()
fmt.Printf("Título: %s, Precio: %d", t.Title(), t.Price())
}
Y una implementación podría ser algo como esto:
package external
// CustomType implementa implícitamente la interfaz MyType
type CustomType struct {
title string
price int
}
func (t CustomType) Title() string { return t.title }
func (t CustomType) Price() int { return t.price }
// CustomTypeGetter implementa implícitamente la interfaz TypeGetter. ¿O no?
type CustomTypeGetter struct {
}
func (g CustomTypeGetter) GetType() CustomType {
return CustomType{"Hola", 42}
}
Luego, el código haría algo como esto:
package main
import "mypackage"
import "external"
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg) // <--- el compilador no permite esto
}
Espero que el ejemplo se explique por sí mismo: no hay acoplamiento entre “mypackage” y el paquete “external”, que se puede reemplazar, substituir por pruebas, etc.
El problema: el compilador se queja de que la llamada a MyHandler
tiene un objeto que implementa:
func GetType() CustomType
, en lugar de:
func GetType() MyType
La única solución que encontré es mover las declaraciones de interfaces (MyType
y TypeGetter
) a un tercer paquete y tanto “mypackage” como “external” pueden usarlo.
Pero quiero evitar eso.
¿No va en contra de la idea de un tercer paquete común el concepto de implementación implícita de interfaces en Go?
¿Hay alguna manera de implementar algo así sin “ligar” los dos paquetes juntos?
davy.ai
Sí, el concepto de implementación implícita de interfaces en Go puede contradecir la idea de un tercer paquete común. En este caso, mover las declaraciones de interfaces a un tercer paquete sería la mejor solución para desacoplar la implementación del código.
Sin embargo, hay una forma de implementar esto sin vincular los dos paquetes. El paquete de implementación puede definir su
CustomTypeGetter
de la siguiente manera:De esta manera, el paquete
external
exporta una función que devuelve una interfazMyType
, cumpliendo así con la interfazTypeGetter
definida enmypackage
. Entonces, en el paquetemain
, puedes usar el objetoexternal.CustomTypeGetter
en la llamada a la funciónmypackage.MyHandler
sin ningún problema:De esta manera, logras desacoplar la implementación y el código mientras sigues cumpliendo con los requisitos de la interfaz.