Patrones de diseño en Go: cuándo y por qué usarlos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Patrones de diseño en Go: no una «religión», sino una herramienta

\n\n

Cuando empecé a escribir en Go, me perseguía la sensación de que todo eso de la «banda de los cuatro» y sus 23 patrones era algo del mundo de Java y C++. Go es tan simple y conciso — ¿para qué necesitamos estas complejidades? Pero cuanto más me sumergía en proyectos reales (microservicios, utilidades CLI, manejadores de API), más a menudo me sorprendía pensando: «Aquí vendría bien un método fábrica» o «Esta montaña de if-else se puede reemplazar con una estrategia».

\n\n

Los patrones de diseño en Go no son un dogma ni un intento de forzar la POO en un lenguaje funcional. Son soluciones probadas para problemas típicos. Ayudan a que el código sea comprobable, flexible y comprensible para los colegas. Y sí, Go deja su huella: debido a la ausencia de herencia clásica y genéricos (hasta la versión 1.18), algunos patrones se transforman y otros se vuelven redundantes.

\n\n

En este artículo no enumeraremos los 23 patrones. En su lugar, analizaremos los 5 patrones más demandados en Golang que realmente serán útiles en proyectos reales. Verá cuándo aplicarlos y cuándo salir corriendo sin mirar atrás.

\n\n

Patrón Singleton en Go: no solo un singleton, sino un singleton a la manera de Go

\n\n

Singleton garantiza que solo haya una instancia de la estructura. En Go, esto se usa a menudo para configuraciones, grupos de conexiones o registradores. Pero hay un matiz: en Go no hay clases estáticas, pero sí sync.Once — la herramienta ideal para la inicialización diferida.

\n\n

Problema sin Singleton

\n

Imagine que tiene una estructura Config que lee la configuración de un archivo. Si cada paquete crea su propia instancia, leerá el archivo 10 veces (lento) o tendrá una condición de carrera.

\n\n

Solución con Singleton

\n
package config\n\nimport (\n    "sync"\n    "encoding/json"\n    "os"\n)\n\ntype Config struct {\n    Port int    `json:"port"`\n    Env  string `json:"env"`\n}\n\nvar (\n    instance *Config\n    once     sync.Once\n)\n\nfunc GetConfig() *Config {\n    once.Do(func() {\n        file, _ := os.Open("config.json")\n        defer file.Close()\n        instance = &Config{}\n        json.NewDecoder(file).Decode(instance)\n    })\n    return instance\n}
\n\n

Cuándo usarlo: cuando se necesita garantizar la unicidad de la instancia (configuraciones, cachés, fábricas).

\n

Cuándo no usarlo: para todo. Singleton es un estado global que dificulta las pruebas. Si se puede pasar la dependencia a través del constructor — pásela.

\n\n

Patrón Factory: cuando la creación de objetos se vuelve compleja

\n\n

Factory Method y Abstract Factory tratan sobre encapsular la lógica de creación de objetos. En Go, esto es especialmente relevante ya que no tenemos constructores en el sentido clásico. En su lugar, usamos funciones constructoras con el prefijo New.

\n\n

Ejemplo: creación de notificaciones

\n

Supongamos que su sistema envía notificaciones por Email, SMS y Push. En lugar de dispersar la lógica de selección por el código, usamos una fábrica.

\n\n
package notification\n\nimport "fmt"\n\ntype Notifier interface {\n    Send(message string) error\n}\n\ntype EmailNotifier struct{}\n\nfunc (e EmailNotifier) Send(message string) error {\n    fmt.Println("Enviando email:", message)\n    return nil\n}\n\ntype SMSNotifier struct{}\n\nfunc (s SMSNotifier) Send(message string) error {\n    fmt.Println("Enviando SMS:", message)\n    return nil\n}\n\nfunc NewNotifier(typ string) Notifier {\n    switch typ {\n    case "email":\n        return EmailNotifier{}\n    case "sms":\n        return SMSNotifier{}\n    default:\n        return nil\n    }\n}
\n\n

Cuándo usarlo: cuando la lógica de creación es compleja (depende del tipo, versión, configuración).

\n

Cuándo no usarlo: si solo tiene un tipo de objeto. Simplemente escriba MyStruct{} o NewMyStruct() sin fábrica.

\n\n

Pa

Blogs

Book Recommendations