Un patrón de diseño es una solución general reutilizable para un problema recurrente en un contexto específico del desarrollo orientado a objetos. En vez de describir una clase concreta, captura la esencia de una colaboración entre objetos para que podamos replicarla en distintos proyectos con las adaptaciones necesarias.
La noción moderna de patrón se popularizó gracias al libro Design Patterns: Elements of Reusable Object-Oriented Software del Gang of Four, donde se formalizaron 23 soluciones clásicas y se estableció una plantilla de documentación ampliamente aceptada dentro de la comunidad de ingeniería de software.
Para que una solución sea considerada patrón debe cumplir tres criterios:
Un patrón no es un fragmento de código copiable literalmente. Se trata de un modelo conceptual que guía el diseño y que se adapta a cada lenguaje, arquitectura o estilo de programación.
La plantilla propuesta por el GoF y enriquecida por posteriores autores incluye elementos que facilitan su comprensión y evaluación:
Registrar estos puntos convierte al patrón en un artefacto vivo que facilita su transmisión dentro de la organización.
Es habitual confundir los patrones con otros conceptos cercanos. Una arquitectura describe la estructura global de un sistema y las decisiones de alto nivel; un framework es un conjunto de componentes reutilizables que proveen funcionalidad y establecen puntos de extensión; una buena práctica es una recomendación general, a menudo respaldada por experiencia, pero que no necesariamente define roles ni colaboraciones precisas. El patrón se sitúa entre estos niveles: es más concreto que una buena práctica y más abstracto que un framework.
Comprender la diferencia nos ayuda a evitar expectativas erróneas: adoptar un patrón no garantiza una arquitectura completa, pero sí brinda piezas de lego probadas para construirla.
Los patrones emergen de la experiencia, no se inventan de la nada. Un equipo detecta que enfrenta un problema recurrente, analiza soluciones previas y abstrae lo que permanece constante. Para verificar la validez del patrón se buscan otros casos en los que funcione y se recopila evidencia de sus resultados.
Este proceso de maduración implica documentar las fuerzas en tensión (por ejemplo, flexibilidad versus simplicidad), registrar las variantes observadas y señalar las situaciones en las que la solución no aplica. Solo así la comunidad puede confiar en el patrón como herramienta de diseño.
Una guía interna de patrones resulta valiosa cuando se mantiene coherente y accesible. Algunas recomendaciones:
Para aterrizar la definición, implementemos un esquema simplificado del patrón Observer, que permite notificar a múltiples objetos ante un cambio de estado. Este patrón aparece en interfaces gráficas, motores de eventos y sistemas de mensajería, y lo implementaremos en C#.
using System.Collections.Generic;
public interface IObservadorStock
{
void Actualizar(string producto, int nuevoNivel);
}
public class RegistroStock
{
private readonly Dictionary<string, int> _niveles = new();
private readonly List<IObservadorStock> _observadores = new();
public void RegistrarObservador(IObservadorStock observador)
{
_observadores.Add(observador);
}
public void ActualizarNivel(string producto, int nivel)
{
_niveles[producto] = nivel;
Notificar(producto, nivel);
}
private void Notificar(string producto, int nivel)
{
foreach (var observador in _observadores)
{
observador.Actualizar(producto, nivel);
}
}
}
public class AlertaCritica : IObservadorStock
{
public void Actualizar(string producto, int nuevoNivel)
{
if (nuevoNivel <= 5)
{
// Enviar alerta a un sistema externo
}
}
}
public class ReporteDiario : IObservadorStock
{
public void Actualizar(string producto, int nuevoNivel)
{
// Registrar el cambio en un informe periódico
}
}
var registro = new RegistroStock();
registro.RegistrarObservador(new AlertaCritica());
registro.RegistrarObservador(new ReporteDiario());
registro.ActualizarNivel("Notebook", 4);
La implementación muestra los elementos clave del patrón: un sujeto que mantiene una lista de observadores, una interfaz común para quienes desean recibir notificaciones y la difusión del evento a todas las partes interesadas. Cada proyecto adaptará detalles como el manejo de concurrencia o la persistencia de los cambios, pero la intención y las colaboraciones permanecen, justificando que lo consideremos un patrón. Veremos el patrón Observer en profundidas más adelante.
El entusiasmo inicial puede llevar a sobrediseñar con patrones innecesarios. Otros tropiezos frecuentes incluyen elegir un patrón solo por familiaridad, ignorar sus consecuencias negativas o documentarlo a medias, dificultando su mantenimiento. Evite estos problemas examinando siempre el contexto y midiendo el impacto real en la base de código.