Menu
Coddy logo textTech

La interfaz como contrato

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 27 de 107.

Considerar las interfaces como contratos te ayuda a diseñar mejores programas en Go. Cuando una función acepta un tipo de interfaz, está diciendo: «No me importa qué tipo concreto me des, siempre y cuando cumpla este contrato».

Este enfoque basado en contratos te permite escribir funciones que se centran en el comportamiento en lugar de en tipos específicos. Considera una función que necesita procesar datos de diversas fuentes:

type DataSource interface {
    FetchData() string
}

func ProcessData(src DataSource) {
    data := src.FetchData()
    fmt.Println("Processing:", data)
}

La función ProcessData no sabe ni le importa si recibe una conexión a una base de datos, un cliente de API o un lector de archivos. Solo requiere que la entrada pueda ejecutar FetchData(). Cualquier tipo que cumpla este contrato funciona.

type Database struct{ ConnectionString string }
func (d Database) FetchData() string { return "data from DB" }

type APIClient struct{ Endpoint string }
func (a APIClient) FetchData() string { return "data from API" }

func main() {
    db := Database{ConnectionString: "localhost"}
    api := APIClient{Endpoint: "https://api.example.com"}
    
    ProcessData(db)   // ¡Funciona!
    ProcessData(api)  // ¡También funciona!
}

Este enfoque de contrato también hace que tu código sea más fácil de probar. Durante las pruebas, puedes crear un tipo simulado que cumpla la interfaz sin necesitar bases de datos reales ni conexiones de red. La función que se está probando no nota la diferencia porque el contrato se cumple.

challenge icon

Desafío

Fácil

Construyamos un sistema de notificaciones que demuestre cómo las interfaces actúan como contratos. Crearás una interfaz Notifier que define qué significa enviar una notificación y, después, implementarás varios canales de notificación que respeten este contrato.

Organizarás tu código en dos archivos:

  • notifiers.go: Define una interfaz Notifier con un único método Notify(message string) string. Después, crea tres estructuras diferentes que satisfagan este contrato:
    • ConsoleNotifier con un campo Prefix
    • FileNotifier con un campo Filename
    • WebhookNotifier con un campo URL
    Cada estructura debe implementar el método Notify para devolver una cadena que describa cómo se enviaría la notificación.
  • main.go: Crea una función llamada BroadcastAlert que acepte un slice de valores Notifier y una cadena de mensaje. Esta función debe llamar a Notify en cada notificador e imprimir los resultados. Lee la configuración de la entrada, crea los tres tipos de notificadores y transmite una alerta a través de todos ellos.

Se proporcionarán las siguientes entradas:

  • Línea 1: Prefijo de la consola
  • Línea 2: Nombre del archivo
  • Línea 3: URL del webhook
  • Línea 4: Mensaje de alerta

Tus métodos Notify deben devolver cadenas con estos formatos:

  • ConsoleNotifier: [Prefix] [message]
  • FileNotifier: Writing to [Filename]: [message]
  • WebhookNotifier: POST [URL]: [message]

Por ejemplo, dadas las entradas ALERT:, log.txt, https://hooks.example.com y Server down!, tu salida debería ser:

ALERT: Server down!
Writing to log.txt: Server down!
POST https://hooks.example.com: Server down!

La ventaja de este diseño es que tu función BroadcastAlert no conoce ni necesita conocer los tipos específicos de notificadores. Solo requiere que cada uno cumpla el contrato Notifier. Más adelante podrías añadir un SlackNotifier o un EmailNotifier sin cambiar la función de transmisión.

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
)

// BroadcastAlert envía un mensaje a través de todos los notifiers
// TODO: Implementa esta función para:
// - Aceptar un slice de valores Notifier y una cadena message
// - Llamar a Notify en cada notifier e imprimir los resultados
func BroadcastAlert(notifiers []Notifier, message string) {
	// TODO: Recorrer los notifiers e imprimir el resultado de cada notificación
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leer el prefijo de consola
	scanner.Scan()
	prefix := scanner.Text()
	
	// Leer el nombre de archivo
	scanner.Scan()
	filename := scanner.Text()
	
	// Leer la URL del webhook
	scanner.Scan()
	url := scanner.Text()
	
	// Leer el mensaje de alerta
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: Crear instancias de los tres tipos de notifier
	// - ConsoleNotifier con el prefijo
	// - FileNotifier con el filename
	// - WebhookNotifier con la URL
	
	// TODO: Crea un slice de Notifier que contenga los tres notifiers
	
	// TODO: Llama a BroadcastAlert con los notifiers y message
	
	_ = prefix
	_ = filename
	_ = url
	_ = message
	fmt.Println("TODO: Implement the solution")
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online