0Pricing
Go Academy · Lección

Composición de interfaces y buenas prácticas

Interfaces pequeñas e inversión de dependencias

Composición de interfaces y buenas prácticas es una lección gratuita de Go Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Go Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Go Academy incluye 4 lecciones en total.

Composición de interfaces

Las interfaces de Go pueden incrustar otras interfaces para componer interfaces más grandes:

package main
import "io"

// io.ReadWriter composes Reader and Writer
type ReadWriter interface {
    io.Reader
    io.Writer
}

// Your own composition:
type Processor interface {
    io.Reader
    Process() error
    io.Closer
}

func main() { _ = (*Processor)(nil) }

Principio de las interfaces pequeñas

Las interfaces de Go más potentes tienen uno o dos métodos. Esto maximiza el número de tipos que pueden implementarlas:

  • io.Reader — 1 método
  • io.Writer — 1 método
  • error — 1 método
  • fmt.Stringer — 1 método

Las interfaces grandes son más difíciles de simular y probar.

Inversión de dependencias

Acepte interfaces en los parámetros de las funciones en lugar de tipos concretos. Esto desacopla su código de implementaciones específicas:

package main
import "fmt"

type Store interface {
    Get(key string) (string, bool)
    Set(key, val string)
}

func cache(s Store, key, value string) {
    if _, ok := s.Get(key); !ok {
        s.Set(key, value)
    }
}

type MapStore struct{ m map[string]string }
func (ms *MapStore) Get(k string) (string, bool) { v, ok := ms.m[k]; return v, ok }
func (ms *MapStore) Set(k, v string) { ms.m[k] = v }

func main() {
    s := &MapStore{m: map[string]string{}}
    cache(s, "x", "hello")
    v, _ := s.Get("x")
    fmt.Println(v)
}

Segregación de interfaces

Divida las interfaces grandes en interfaces más pequeñas y centradas. Los clientes solo dependen de los métodos que utilizan:

package main

// Bad: large interface forces all methods
type BigStorage interface {
    Read(key string) string
    Write(key, val string)
    Delete(key string)
    List() []string
    Backup() error
}

// Good: small, focused interfaces
type Reader interface{ Read(key string) string }
type Writer interface{ Write(key, val string) }
type Lister interface{ List() []string }

func readAll(r Reader) {} // only needs Read

func main() { _ = readAll }

Devolver tipos concretos

Los constructores deben devolver tipos concretos, no interfaces. Los llamadores siempre pueden asignar un tipo concreto a una variable de interfaz:

package main

type Logger interface{ Log(string) }
type ConsoleLogger struct{}
func (c *ConsoleLogger) Log(s string) {}

// Good: return concrete *ConsoleLogger
func NewConsoleLogger() *ConsoleLogger { return &ConsoleLogger{} }

// Avoid: return Logger (hides the concrete type)
// func NewConsoleLogger() Logger { return &ConsoleLogger{} }

func main() { _ = NewConsoleLogger() }

Contaminación de interfaces

No cree una interfaz para cada tipo «por si acaso». Cree interfaces únicamente cuando:

  • Ya tenga varias implementaciones o vaya a tenerlas pronto
  • Necesite simular la dependencia en las pruebas
  • Esté creando una biblioteca y quiera desacoplar a los llamadores

Incrustar interfaces para ampliar

Incruste una interfaz para añadir métodos opcionales con valores predeterminados:

package main
import "fmt"

type Handler interface{ Handle(msg string) }
type NamedHandler interface {
    Handler
    Name() string
}

func dispatch(h Handler) {
    if nh, ok := h.(NamedHandler); ok {
        fmt.Printf("[%s] ", nh.Name())
    }
    h.Handle("event")
}

type MyHandler struct{}
func (m MyHandler) Handle(msg string)  { fmt.Println(msg) }
func (m MyHandler) Name() string       { return "my" }

func main() { dispatch(MyHandler{}) }

Simulación con interfaces

Defina las dependencias como interfaces e inyecte simulaciones en las pruebas:

package main
import "fmt"

type Clock interface{ Now() int64 }

type MockClock struct{ T int64 }
func (m MockClock) Now() int64 { return m.T }

func isExpired(c Clock, expiresAt int64) bool {
    return c.Now() > expiresAt
}

func main() {
    mc := MockClock{T: 1000}
    fmt.Println(isExpired(mc, 500))  // true
    fmt.Println(isExpired(mc, 1500)) // false
}

Incrustación de interfaces frente a incrustación de structs para la reutilización

Utilice la incrustación de interfaces para componer API y la incrustación de structs para reutilizar código. Cumplen propósitos distintos y no deben confundirse.

Detectar el cumplimiento de interfaces en tiempo de compilación

Utilice una comprobación en tiempo de compilación con el identificador en blanco para verificar que su tipo satisface una interfaz:

package main

type Doer interface{ Do() }
type MyType struct{}
func (m *MyType) Do() {}

// Compile-time check — no runtime cost
var _ Doer = (*MyType)(nil)

func main() {}

Comprobación rápida

¿Cuándo debe definir una interfaz nueva en Go?

Repaso: prácticas recomendadas para interfaces

Ideas clave:

  • Mantenga las interfaces pequeñas: uno o dos métodos
  • Componga interfaces a partir de otras más pequeñas
  • Acepte interfaces y devuelva tipos concretos
  • Cree interfaces para facilitar las pruebas y admitir varias implementaciones
  • Utilice una comprobación en tiempo de compilación mediante una asignación al identificador en blanco

Ejercicio práctico

Diseñe una interfaz Notifier con Notify(msg string) error. Impleméntela para EmailNotifier y SMSNotifier. Escriba una función broadcast que envíe notificaciones a un []Notifier.

Preguntas frecuentes

¿La lección «Composición de interfaces y buenas prácticas» es gratis?

Sí — el texto completo de «Composición de interfaces y buenas prácticas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Go Academy, actualiza a CoddyKit PRO. El curso de Go Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Composición de interfaces y buenas prácticas»?

Interfaces pequeñas e inversión de dependencias Practicas Go Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Go Academy?

No se requiere experiencia previa. Go Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Composición de interfaces y buenas prácticas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Go Academy?

Sí. Cada lección de Go Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Definición e implementación de interfaces
  2. Interfaces principales de la biblioteca estándar
  3. Aserciones de tipo y switches de tipo
  4. Composición de interfaces y buenas prácticas
← Volver a Go Academy