2. ¿Qué es un patrón de diseño?

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.

2.1 Definición precisa y alcance

Para que una solución sea considerada patrón debe cumplir tres criterios:

  • Repetibilidad: ha sido aplicada con éxito en múltiples sistemas y contextos, demostrando que no es una ocurrencia aislada.
  • Abstracta pero accionable: describe la estructura y las interacciones entre clases u objetos sin imponer detalles de implementación.
  • Contextualizada: especifica cuándo se debe aplicar y qué fuerzas (limitaciones técnicas, requisitos del dominio, objetivos de mantenimiento) equilibra.

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.

2.2 Componentes esenciales de un patrón

La plantilla propuesta por el GoF y enriquecida por posteriores autores incluye elementos que facilitan su comprensión y evaluación:

  • Nombre y clasificación: permite ubicar el patrón en una categoría (creacional, estructural o de comportamiento) y referenciarlo en discusiones técnicas.
  • Intención: explica la finalidad de la solución en una frase breve.
  • Problema y contexto: delimita las situaciones típicas en las que el patrón ofrece valor.
  • Participantes: describe el rol de cada clase u objeto involucrado.
  • Colaboraciones: detalla cómo se comunican los participantes para cumplir la intención.
  • Consecuencias: analiza ventajas, costos y trade-offs (pérdida de una cosa y la ganancia de otra) que implica adoptar el patrón.
  • Implementación y ejemplos: incluyen consideraciones prácticas, diagramas y fragmentos de código que ilustran la idea.

Registrar estos puntos convierte al patrón en un artefacto vivo que facilita su transmisión dentro de la organización.

2.3 Diferencias con arquitectura, frameworks y buenas prácticas

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.

2.4 Identificación y maduración de un patrón

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.

2.5 Cómo documentar patrones en un equipo

Una guía interna de patrones resulta valiosa cuando se mantiene coherente y accesible. Algunas recomendaciones:

  • Usar lenguaje común: conservar los nombres aceptados internacionalmente facilita la comunicación con profesionales externos.
  • Incluir diagramas: un diagrama de clases o de secuencia complementa el texto y acelera el entendimiento.
  • Conectar con el dominio: ilustrar el patrón con ejemplos del negocio evita que quede como un ejercicio teórico.
  • Mencionar anti-patrones relacionados: advertir sobre errores habituales ayuda a tomar decisiones más informadas.
  • Actualizar con retrospectivas: revisar la documentación luego de cada proyecto mantiene los patrones alineados con la realidad del equipo.

2.6 Ejemplo práctico en Java

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 Java.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

interface ObservadorStock {
    void actualizar(String producto, int nuevoNivel);
}

class RegistroStock {
    private final Map<String, Integer> niveles = new HashMap<>();
    private final List<ObservadorStock> observadores = new ArrayList<>();

    void registrarObservador(ObservadorStock observador) {
        observadores.add(observador);
    }

    void actualizarNivel(String producto, int nivel) {
        niveles.put(producto, nivel);
        notificar(producto, nivel);
    }

    private void notificar(String producto, int nivel) {
        for (ObservadorStock observador : observadores) {
            observador.actualizar(producto, nivel);
        }
    }
}

class AlertaCritica implements ObservadorStock {
    public void actualizar(String producto, int nuevoNivel) {
        if (nuevoNivel <= 5) {
            // Enviar alerta a un sistema externo
        }
    }
}

class ReporteDiario implements ObservadorStock {
    public void actualizar(String producto, int nuevoNivel) {
        // Registrar el cambio en un informe periódico
    }
}

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.

2.7 Errores típicos al aplicar patrones

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.