es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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?

Tags:  ,

Answer

  1. Avatar for 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:

    package external
    
    import "mypackage"
    
    // CustomType implementa 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 struct
    type CustomTypeGetter struct{}
    
    // GetType método de CustomTypeGetter devuelve una interfaz MyType
    func (g CustomTypeGetter) GetType() mypackage.MyType {
        return CustomType{title: "Hola", price: 42}
    }
    

    De esta manera, el paquete external exporta una función que devuelve una interfaz MyType, cumpliendo así con la interfaz TypeGetter definida en mypackage. Entonces, en el paquete main, puedes usar el objeto external.CustomTypeGetter en la llamada a la función mypackage.MyHandler sin ningún problema:

    package main
    
    import (
        "fmt"
        "mypackage"
        "external"
    )
    
    func main() {
        tg := external.CustomTypeGetter{}
        mypackage.MyHandler(tg)
    }
    

    De esta manera, logras desacoplar la implementación y el código mientras sigues cumpliendo con los requisitos de la interfaz.

Comments are closed.