El catálogo está completo: 23 patrones, tres familias, y PideYa entera como demostración. Pero los problemas reales no llegan etiquetados — ningún ticket de Jira dice "aplicar Strategy aquí". Llegan como síntomas: un switch que crece, una clase que nadie quiere tocar, un requisito que obliga a cambiar cinco ficheros. Esta lección enseña el método para ir del síntoma al patrón (o a ningún patrón, que también es una elección): nombrar el problema antes que la solución, analizar sus fuerzas, hacer las preguntas de diagnóstico correctas y validar la respuesta antes de escribir una línea. Es la primera lección del oficio: la diferencia entre tener las herramientas y ser buen carpintero.

Contenido

  1. Primero el problema, después el patrón
  2. El catálogo de fuerzas: qué varía y qué debe permanecer estable
  3. Preguntas de diagnóstico por familia
  4. El árbol de decisión global del catálogo GoF
  5. Tres casos de PideYa resueltos con el método
  6. "Espera hasta que duela": el patrón que no se elige por adelantado
  7. Ejercicios y conclusión

Primero el problema, después el patrón

El error más común al aplicar patrones no es elegir mal entre Strategy y State: es empezar por el patrón. Quien pregunta "¿dónde puedo meter un Visitor?" ya perdió — tiene una solución buscando problema. El método correcto invierte el orden:

  1. Describe el problema sin nombrar ningún patrón. En una o dos frases, en lenguaje de negocio y de código: "cada vez que marketing añade un tipo de cupón, tocamos la clase de checkout y se nos escapa algún caso".
  2. Identifica las fuerzas. ¿Qué cambia a menudo? ¿Qué debe quedar intacto? ¿Quién no debe conocer a quién? (siguiente apartado).
  3. Clasifica el problema por familia: ¿va de crear objetos, de componer estructuras o de coordinar conducta?
  4. Aplica las preguntas de diagnóstico de esa familia y llega a uno o dos candidatos.
  5. Valida contra la intención y el careo. Lee la sección "aplicabilidad" del candidato y su careo con el patrón vecino (las comparativas existen para esto). Si la intención del patrón no coincide con tu frase del paso 1, vuelve a empezar.
  6. Pasa los cinco filtros de la balanza: problema nombrable, eje de cambio real, dolor presente, equipo preparado, beneficio mayor que coste.

Fíjate: el patrón aparece en el paso 4, no en el 1. Todo lo anterior es análisis del problema — y es la parte que distingue al profesional.

El catálogo de fuerzas: qué varía y qué debe permanecer estable

Los GoF lo escribieron en el prólogo y es la frase más útil del libro: "encapsula lo que varía". Cada patrón protege una zona estable de una zona variable concreta. Identificar el eje de variación de tu problema es identificar media respuesta:

Lo que varía (o quieres poder variar) Lo que debe permanecer estable Familia / candidatos
La clase concreta que se instancia El código que la usa Factory Method, Abstract Factory
Cómo se construye un objeto complejo Su representación final e invariantes Builder
El punto de partida de un objeto nuevo El proceso que lo consume Prototype
La interfaz que ofrece un tercero La interfaz que tu código espera Adapter
Dos dimensiones independientes a la vez Que no exploten combinadas en subclases Bridge
Cuántas responsabilidades extra lleva un objeto Su interfaz y su núcleo Decorator
La estructura interna (hoja o grupo) El tratamiento uniforme desde fuera Composite
Los pasos internos de un proceso multiclase La llamada única del cliente Facade
El algoritmo con que se hace algo El contexto que lo invoca Strategy
Lo permitido según la etapa de vida Las operaciones que el cliente invoca State
Quiénes reaccionan a un cambio El objeto que cambia Observer
Quién atiende una petición El emisor de la petición Chain of Responsibility
Las operaciones sobre una estructura Las clases de la estructura Visitor
Pasos concretos de un flujo El esqueleto del flujo Template Method

La tabla no sustituye a las lecciones: es el índice inverso. Tu trabajo ante un problema real es rellenar la primera columna con honestidad — y si no puedes ("todo puede cambiar" no es una respuesta), es que aún no entiendes el problema lo suficiente para meterle un patrón.

Dos preguntas complementarias afinan las fuerzas:

  • ¿La variación es de datos o de comportamiento? Si las variantes solo difieren en valores (tarifa 2,99 vs. 4,99), basta configuración o un enum; los patrones pagan cuando difiere el código.
  • ¿Quién decide la variante y cuándo? ¿El programador al compilar (herencia puede bastar), la configuración al arrancar (fábricas, inyección), o el usuario/estado en caliente (Strategy, State)?

Preguntas de diagnóstico por familia

Antes de bajar a patrones concretos, clasifica el problema. Tres preguntas de triaje:

  • ¿El dolor aparece al escribir new? — quién crea, cuál variante, con cuántos argumentos, con qué coste → familia creacional.
  • ¿El dolor aparece al dibujar el diagrama de clases? — interfaces que no encajan, jerarquías que explotan, subsistemas tentaculares, objetos carísimos → familia estructural.
  • ¿El dolor aparece al seguir el flujo en ejecución? — quién llama a quién, quién se entera de qué, dónde vive un algoritmo, qué se puede deshacer → familia de comportamiento.

Y dentro de cada familia, las preguntas que ya conoces de las comparativas — aquí condensadas:

Familia Pregunta de diagnóstico Si la respuesta es sí...
Creacional ¿El cliente sabe qué quiere pero no cuál clase concreta? Factory Method / Abstract Factory
Creacional ¿La construcción tiene muchos opcionales o pasos con orden? Builder
Creacional ¿Crear desde cero es caro o el punto de partida es "uno como ese"? Prototype
Creacional ¿De verdad debe existir solo uno... y no basta con inyectarlo? Singleton (con la crítica de 02-02)
Estructural ¿Existe código correcto con la interfaz equivocada? Adapter
Estructural ¿Hay parte-todo con tratamiento uniforme? Composite
Estructural ¿Hay que sumar responsabilidades sin tocar la clase ni subclasificar? Decorator / Proxy (según quién controle: careo en 03-09)
Comportamiento ¿Muchos deben enterarse de que uno cambió, sin acoplarse? Observer
Comportamiento ¿Lo permitido depende de la etapa, con transiciones? State
Comportamiento ¿Hay algoritmos alternativos elegidos desde fuera? Strategy
Comportamiento ¿Las peticiones deben encolarse, auditarse o deshacerse? Command

El árbol de decisión global

Las comparativas de cada módulo (creacionales, estructurales, comportamiento) contienen los árboles finos por familia. Este es el nivel superior que te deja en la puerta del árbol correcto:

flowchart TD
    A[Problema de diseño<br/>nombrado sin citar patrones] --> B{¿Dónde duele?}
    B -- "Al crear objetos:<br/>quién, cuál, cómo, cuántos" --> C[Familia CREACIONAL]
    B -- "En la estructura:<br/>interfaces, jerarquías,<br/>composición, coste" --> D[Familia ESTRUCTURAL]
    B -- "En la conducta:<br/>flujo, avisos, algoritmos,<br/>estado, historial" --> E[Familia COMPORTAMIENTO]

    C --> C1{¿Varía la clase, la<br/>construcción o el origen?}
    C1 -- Clase concreta --> C2[Factory Method /<br/>Abstract Factory]
    C1 -- Construcción compleja --> C3[Builder]
    C1 -- Copiar un existente --> C4[Prototype]
    C1 -- Instancia única --> C5[Singleton... o inyección]
    C -.-> CREF[Árbol fino: lección 02-07]

    D --> D1{¿Adaptar, componer,<br/>envolver o simplificar?}
    D1 -- Interfaz incompatible --> D2[Adapter]
    D1 -- "Parte-todo / 2 dimensiones" --> D3[Composite / Bridge]
    D1 -- Envolver con algo más --> D4[Decorator / Proxy]
    D1 -- Subsistema complejo --> D5[Facade / Flyweight]
    D -.-> DREF[Árbol fino: lección 03-09]

    E --> E1{¿Avisar, encapsular petición,<br/>variar conducta u operar<br/>sobre estructuras?}
    E1 -- Avisar / coordinar --> E2[Observer / Mediator]
    E1 -- Petición como objeto --> E3[Command / Chain / Interpreter]
    E1 -- Variar comportamiento --> E4[Strategy / State /<br/>Template Method]
    E1 -- Estructuras y estado --> E5[Iterator / Visitor / Memento]
    E -.-> EREF[Árbol fino: lección 04-13]

Úsalo como se usa una brújula: te orienta, no te lleva a la puerta. La confirmación final siempre es contra la intención del patrón y su careo con el vecino confundible.

Tres casos de PideYa resueltos con el método

Caso creacional: los contratos de restaurante

El ticket: "Al dar de alta un restaurante hay que generar su contrato. Hoy hay dos tipos (comisión estándar y tarifa plana premium) y legal anuncia un tercero (marketplace puro) para el trimestre que viene. El alta hoy hace new ContratoComision(...) o new ContratoPlano(...) según un if sobre un string."

  1. Problema sin patrón: "el proceso de alta debe generar el contrato correcto sin conocer las clases concretas de contrato, porque los tipos crecen".
  2. Fuerzas: varía la clase concreta instanciada; debe permanecer estable el flujo de alta (validar → crear contrato → firmar → activar). La variación es de comportamiento (cada contrato calcula liquidaciones distinto), no solo de datos.
  3. Familia: el dolor está en el new → creacional.
  4. Diagnóstico: ¿el cliente sabe qué quiere ("un contrato para este restaurante") pero no cuál clase? Sí. ¿Familias completas de productos coordinados por mercado? No, es un producto suelto. → Factory Method (o su variante con registro de Suppliers, como el RegistroNotificadores de 02-03).
  5. Validación: intención de Factory Method — "definir una interfaz para crear un objeto, dejando a las subclases decidir cuál" — coincide. Descartado Abstract Factory: no hay familia de productos que deban ser coherentes entre sí.
  6. Filtros: eje de cambio real (tercer tipo en roadmap), dolor presente (el if ya se duplicó en dos sitios). Adelante.

Caso estructural: el agregador de opiniones

El ticket: "Integramos las reseñas de un agregador externo. Su SDK devuelve ReviewDTO con getStars() (0-10) y getBody(); nuestro código de fichas espera Opinion con puntuacion() (0-5) y texto()."

  1. Problema sin patrón: "código externo correcto, interfaz que no encaja con la nuestra".
  2. Fuerzas: varía el proveedor externo y su interfaz; debe permanecer estable nuestro dominio (Opinion y todo lo que la consume). No queremos que ReviewDTO se filtre por el código.
  3. Familia: el dolor es de encaje de interfaces → estructural.
  4. Diagnóstico: ¿existe código correcto con la interfaz equivocada? Sí, literalmente. → Adapter (AdaptadorOpinionesExternas implements Opinion), el mismo movimiento que el AdaptadorPayPal de 03-02.
  5. Validación: descartados Facade (no simplificamos un subsistema propio, traducimos uno ajeno) y Decorator (no añadimos responsabilidades, convertimos interfaz).
  6. Filtros: el dolor es inmediato (sin adapter, la conversión 0-10 → 0-5 se repetiría en cada punto de uso). Adelante.

Caso de comportamiento: la propina al repartidor

El ticket: "Tras la entrega, el cliente puede dejar propina. Cuando la deja, hay que: abonarla al repartidor, reflejarla en su resumen semanal, sumarla a las métricas de la zona y — pronto — dispararle una notificación de agradecimiento."

  1. Problema sin patrón: "un hecho puntual (propina registrada) interesa a un número creciente de módulos que no deben acoplarse al que lo produce".
  2. Fuerzas: varía quiénes reaccionan (hoy tres, mañana cuatro); debe permanecer estable el registro de la propina. Nadie dirige un protocolo: cada interesado reacciona a lo suyo.
  3. Familia: el dolor está en el flujo de avisos → comportamiento.
  4. Diagnóstico: ¿muchos deben enterarse de que uno cambió? Sí. ¿Hay protocolo que dirigir entre ellos? No. → Observer, reutilizando la infraestructura de eventos que ya difunde las transiciones del pedido (04-08).
  5. Validación: descartado Mediator con la prueba del algodón de 04-13 — el emisor no espera coordinación, solo que quien quiera se entere.
  6. Filtros: el cuarto interesado ya está en roadmap; sin Observer, registrar la propina acumularía dependencias hacia contabilidad, métricas y notificaciones. Adelante.

Nota el ritmo común: en los tres casos, el patrón fue la conclusión de seis pasos, no el punto de partida. Y en los tres, hubo un descarte explícito — saber por qué no es el vecino vale tanto como saber por qué sí es el elegido.

"Espera hasta que duela"

El método tiene una salida más, y es la más frecuente en código sano: todavía ninguno.

Elegir patrón por adelantado — "seguro que las promociones acabarán necesitando Interpreter, lo dejo montado" — es apostar a ciegas sobre el eje de variación futuro, y la apuesta casi siempre falla: el cambio llega, pero por otro lado, y la estructura especulativa estorba en vez de ayudar. La disciplina profesional es la contraria:

  1. Escribe la versión simple (el if, la llamada directa, el enum) y mantenla limpia.
  2. Anota la intención si intuyes el eje de cambio: un comentario "si aparece un tercer tipo de contrato, extraer Factory" cuesta cero y guía al siguiente.
  3. Vigila los síntomas: la segunda duplicación, el tercer caso del switch, el test que ya no se puede escribir. Ese es el dolor real.
  4. Cuando duela, refactoriza hacia el patrón — que es barato precisamente porque el código simple es fácil de mover. Cómo hacerlo con red de seguridad es la lección 05-04.

La regla de tres es un buen calibrador: la primera vez escribes directo, la segunda duplicas con cargo de conciencia, la tercera extraes la abstracción — porque con tres casos ya ves el eje de variación real en vez de imaginarlo. Los patrones se ganan, no se plantan: era la regla de oro de 01-06, y este módulo la convierte en método.

Errores Comunes y Consejos

  • Empezar por el patrón ("¿dónde uso un Observer?"). Es la solución en busca de problema. Antídoto: obligarte a escribir la frase del problema sin nombrar patrones; si no sale, no hay problema todavía.
  • Elegir por parecido estructural, no por intención. Strategy y State comparten diagrama; Chain y Decorator también. El diagrama nunca decide: decide la intención, y los careos de las comparativas existen para eso.
  • Confundir variación de datos con variación de comportamiento. Si las variantes solo cambian valores, un mapa de configuración vence a cualquier patrón.
  • Quedarse con el primer candidato. Fuerza siempre un descarte explícito ("es X y no Y porque..."). Si no puedes articular el descarte, no has terminado el diagnóstico.
  • Olvidar la opción "ninguno". El árbol global tiene una rama invisible que sale de la raíz: "el código simple aún no duele → espera". Es la rama correcta más veces de las que el entusiasmo admite.
  • Consejo: pon fecha a las esperas. "Hoy no; revisar cuando marketing lance el tercer tipo de cupón" convierte la prudencia en decisión registrada, no en olvido.

Ejercicios

Ejercicio 1: del ticket al diagnóstico

Aplica los seis pasos del método a este ticket de PideYa: "Los restaurantes premium quieren personalizar el ticket que se imprime en cocina: unos añaden su logo, otros un mensaje del chef, otros el desglose de alérgenos — y cualquier combinación de los tres. Hoy hay una subclase de TicketCocina por combinación y ya van cinco". Nombra fuerzas, familia, candidato, y el patrón que descartaste.

Ejercicio 2: ¿patrón o espera?

Para cada situación, decide patrón concreto o espera (con la versión simple que dejarías), justificando con las fuerzas:

  1. "El cálculo de la comisión aplica un porcentaje distinto por tipo de restaurante; los tipos son tres, estables desde hace dos años, y solo difieren en el número."
  2. "Al confirmar un pedido hay que avisar a cocina. Solo a cocina. No hay nada más previsto."
  3. "El estado del pedido hoy es un enum con switch en cuatro métodos; soporte pide añadir el estado EN_ESPERA_RESTAURANTE con reglas propias de cancelación, y es el segundo estado nuevo este año."

Ejercicio 3: reconstruir el diagnóstico

Un compañero propone: "para los cupones descuento, montamos un Abstract Factory con una fábrica por tipo de cupón". Los cupones son: porcentaje sobre el total, cantidad fija, y envío gratis — un solo objeto cada uno, sin familias coordinadas. Escribe (a) qué pregunta de diagnóstico falló en su análisis, (b) qué candidato sale del método bien aplicado, (c) cómo se lo explicarías sin desautorizarlo.

Soluciones

Solución 1: (1) Problema: "añadir extras opcionales y combinables al ticket sin una subclase por combinación". (2) Fuerzas: varían los añadidos y sus combinaciones; estable el ticket base y su interfaz. (3) Familia: estructural — el dolor es la explosión de la jerarquía. (4) Diagnóstico: ¿sumar responsabilidades sin tocar la clase, componibles en caliente? → Decorator, el mismo movimiento que los extras de plato de 03-05. (5) Descarte: Template Method fijaría las variantes por herencia y reproduciría la explosión combinatoria; Strategy variaría el algoritmo entero de impresión, pero aquí las piezas se apilan, no se sustituyen. (6) Filtros: cinco subclases ya duelen — adelante.

Solución 2: (1) Espera: la variación es de datos (un porcentaje), no de comportamiento — un Map<TipoRestaurante, BigDecimal> o el propio enum con un campo lo resuelve; Strategy sería envoltorio vacío. (2) Espera: un solo receptor sin previsión de más — llamada directa con la dependencia inyectada (DIP, testeable), y nota de intención "si aparecen más interesados, Observer". Montar Observer para un observador es la catedral del email de bienvenida. (3) Patrón: State — segundo estado nuevo en un año (eje de cambio real y recurrente), reglas por estado, switch repetido en cuatro métodos (dolor presente). El diagnóstico y la mecánica están en 04-09; cómo migrar el switch sin romper nada, en 05-04.

Solución 3: (a) Falló "¿hay familias de productos que deban ser coherentes entre sí?" — Abstract Factory paga cuando se crean varios productos coordinados (la FabricaMercado creaba pasarela + impuestos + ticket); aquí cada cupón es un producto suelto. (b) Las fuerzas reales: varía el algoritmo de descuento, estable el checkout que lo aplica → Strategy (ReglaDescuento con tres implementaciones), y como mucho un Factory Method simple si la creación desde el código del cupón lo pide. (c) Reconociendo lo acertado del instinto ("has visto bien que la creación no debe estar en el checkout") y reconduciendo con la pregunta, no con la conclusión: "¿qué familia de objetos coordinados crea cada fábrica?" — la pregunta correcta deja que el propio compañero llegue al descarte.

Conclusión

Ya tienes el método: problema nombrado sin patrones, fuerzas sobre la mesa (qué varía, qué queda estable), triaje por familia, preguntas de diagnóstico, validación contra la intención con descarte explícito, y los filtros de la balanza como último control — con la salida "espera hasta que duela" como resultado legítimo y frecuente. Es el mismo camino en cada familia, y los tres casos de PideYa lo demuestran paso a paso. Pero el método se ha entrenado aquí con problemas de una sola respuesta; el código real teje varios patrones en una misma funcionalidad, y ahí las decisiones se condicionan unas a otras. Ver el método funcionando a escala — el flujo completo de un pedido, y un módulo nuevo construido desde cero eligiendo cada pieza — es la siguiente lección: Ejemplos Prácticos de Uso de Patrones.

Curso de Patrones de Diseño de Software

Módulo 1: Introducción a los Patrones de Diseño

Módulo 2: Patrones Creacionales

Módulo 3: Patrones Estructurales

Módulo 4: Patrones de Comportamiento

Módulo 5: Aplicación de Patrones de Diseño

Módulo 6: Patrones de Diseño Avanzados

Módulo 7: Recursos Adicionales y Conclusión

© Copyright 2026. Todos los derechos reservados