Si este curso solo te enseñara los 23 patrones, te haría un flaco favor: saldrías con un martillo nuevo y todo te parecería un clavo. El desarrollador que acaba de aprender patrones y los aplica en todas partes es un cliché tan real que tiene nombre propio en la profesión ("patternitis"). Esta última lección del módulo introduce el contrapeso: qué ganan de verdad los equipos que usan patrones, qué pagan por ellos, y —lo más valioso— con qué criterios decidir en cada caso si un patrón merece la pena. Con esta balanza bien calibrada estarás listo para estudiar los patrones uno a uno sin perder el juicio crítico.

Contenido

  1. Las ventajas reales de los patrones
  2. Los costes y riesgos
  3. El riesgo mayor: la sobreingeniería
  4. Criterios para decidir si aplicar un patrón
  5. Tabla resumen de la balanza
  6. Cómo estudiar los próximos módulos con esta balanza en mente

Las ventajas reales de los patrones

Vocabulario común: la ventaja más subestimada

La ganancia más inmediata no está en el código sino en la comunicación. Compara estas dos frases en una reunión del equipo de PideYa:

«He hecho una interfaz con un método de cálculo, y luego varias clases que la implementan, una por cada forma de calcular el envío, y la clase del pedido recibe una de ellas y la llama sin saber cuál es...»

«El cálculo del envío es una Strategy.»

La segunda frase transmite en cinco palabras la estructura completa, las responsabilidades y hasta las consecuencias esperables, porque ambos interlocutores comparten el catálogo. Este vocabulario opera en todas partes: revisiones de código, documentación, nombres de clases (PedidoBuilder, NotificadorObserver), entrevistas técnicas y la propia documentación de las librerías que usas.

Soluciones probadas: no pagar la novatada

Un patrón condensa décadas de ensayo y error de miles de equipos. Cuando en PideYa haya que notificar cambios de pedido a partes interesadas (el problema de la lección 1), no partiremos de cero: la solución catalogada ya tiene resueltos los problemas de segundo orden que tú aún no has visto venir (¿qué pasa si un suscriptor falla? ¿y si se da de baja durante la notificación?). Las secciones de "Implementación" y "Consecuencias" de un patrón son emboscadas ya desactivadas.

Mantenibilidad y evolución

Los patrones aplican los principios de diseño de forma sistemática, y eso se traduce en código que absorbe cambios: añadir una pasarela de pago, un canal de notificación o una promoción sin tocar lo que funciona (OCP), y en código testeable, porque las abstracciones que introducen los patrones son exactamente los puntos donde inyectar dobles de prueba (DIP).

Legibilidad para quien llega después

Un diseño con patrones bien aplicados es un diseño autodocumentado para cualquier desarrollador formado: quien abre el proyecto y ve un CarritoMemento o un AdaptadorPasarelaStripe sabe qué esperar antes de leer una línea del cuerpo. Se reduce el coste de incorporación al equipo y el riesgo de "solo Juan entiende esta parte".

Puente hacia frameworks y plataformas

Como vimos en la lección de historia, los frameworks están construidos con patrones. Conocerlos convierte la "magia" de Spring, JPA o Android en mecanismos reconocibles, y te permite extender esos frameworks por los puntos de extensión que sus autores diseñaron (que son, casi siempre, patrones expuestos).

Los costes y riesgos

Ningún patrón es gratis. Los costes son reales y conviene mirarlos de frente:

Complejidad accidental e indirección

Todo patrón añade piezas: interfaces, clases pequeñas, saltos entre ficheros. Donde había un método con tres if, puede acabar habiendo una interfaz, cuatro implementaciones y una fábrica. Si la flexibilidad que compran esas piezas se usa, es un buen negocio; si no, has cambiado tres if legibles por siete ficheros que hay que abrir en orden para entender qué pasa. A esa complejidad que no viene del problema sino de la solución se la llama complejidad accidental, y es el impuesto básico de los patrones.

Curva de aprendizaje y barrera de entrada

El vocabulario común solo funciona si todo el equipo lo habla. En un equipo donde la mitad no conoce los patrones, un diseño lleno de ellos no comunica: intimida. El código con patrones es más legible para quien los conoce y menos para quien no; esto es un coste organizativo real que debes considerar al decidir cuánto patrón introduce tu diseño.

Aplicar un patrón donde no toca

El riesgo más dañino no es implementar mal un patrón, sino implementar bien el patrón equivocado (o uno innecesario). Síntomas típicos:

  • Elegir el patrón por la solución ("me apetece usar un Builder") en lugar de por el problema.
  • Forzar el problema para que encaje en el patrón, en vez de al revés.
  • Introducir la flexibilidad de un patrón en un eje donde el cambio nunca llega (violación de YAGNI con disfraz elegante).

Cuando estos errores se sistematizan, cristalizan en antipatrones: soluciones recurrentes que parecen buenas y son dañinas. Les dedicaremos una lección completa en el módulo 5 (Antipatrones); de momento, quédate con que existen y con que varios nacen de patrones mal aplicados.

Coste de rendimiento (menor, pero existe)

La indirección tiene un coste de ejecución (llamadas virtuales, objetos extra, memoria). En el 99% del código de una aplicación como PideYa es despreciable frente al coste de una consulta a base de datos; solo en puntos calientes extremos llega a importar. Es el menos importante de los costes, pero citarlo es honesto.

El riesgo mayor: la sobreingeniería

Merece sección propia porque es la enfermedad profesional de quien acaba de aprender patrones. Sobreingeniería es construir más estructura de la que el problema necesita. Veámosla en PideYa:

El problema real: PideYa necesita enviar un email de bienvenida al registrarse un cliente. Uno, sencillo, siempre igual.

La solución sobreingenierizada (no imites esto):

// Interfaz para "flexibilidad futura"
public interface EstrategiaBienvenida { void ejecutar(Cliente c); }

// Fábrica abstracta de estrategias "por si hay más canales"
public interface FabricaBienvenidas { EstrategiaBienvenida crear(); }

// Registro con instancia única de la fábrica de fábricas...
public class RegistroFabricas { /* ... */ }

// ...y la única implementación real, escondida al fondo:
public class BienvenidaEmail implements EstrategiaBienvenida {
    public void ejecutar(Cliente c) { /* enviar el email */ }
}

La solución proporcionada:

public class ServicioRegistro {
    private final ServicioEmail email;   // inyectado: testeable (DIP)

    public ServicioRegistro(ServicioEmail email) { this.email = email; }

    public void registrar(Cliente cliente) {
        // ...alta del cliente...
        email.enviarBienvenida(cliente);
    }
}

La segunda versión respeta DIP (dependencia inyectada, testeable) sin montar ninguna catedral. Si algún día marketing pide bienvenidas por SMS y email y push configurables por país... ese día habrá un problema real que justifique más estructura, y refactorizar hacia ella será sencillo precisamente porque el código es simple. La flexibilidad especulativa nunca sale gratis y casi nunca acierta con el eje del cambio futuro.

Regla de oro: los patrones se ganan, no se plantan. Se llega a ellos cuando el problema aprieta, no "por si acaso".

Criterios para decidir si aplicar un patrón

Ante la tentación de aplicar un patrón, pásala por estos filtros, en orden:

  1. ¿Puedo nombrar el problema sin nombrar el patrón? Describe el problema y sus fuerzas en una frase ("necesitamos añadir promociones sin tocar el cálculo"). Si solo sabes decir "quiero usar X", no tienes un problema: tienes ganas de usar X.
  2. ¿El cambio que el patrón facilita es real o especulativo? ¿Ha ocurrido ya al menos una vez, está en el roadmap, o es una corazonada? Los patrones pagan su coste cuando el eje de variación es real (las promociones de PideYa cambian cada mes: real; "quizá algún día soportemos criptomonedas": corazonada).
  3. ¿La alternativa simple duele ya? Mira el código actual: ¿hay síntomas concretos (duplicación al añadir casos, cadenas de if crecientes, tests imposibles, clases que cambian por motivos ajenos)? Si el código simple aún no duele, suele ser pronto.
  4. ¿El equipo podrá mantenerlo? Un diseño que solo tú entiendes es un pasivo, no un activo. Si introduces un patrón poco conocido, acompáñalo: nómbralo en el código y comenta la intención.
  5. ¿El coste queda por debajo del beneficio? Cuenta las piezas que añade (interfaces, clases, saltos) y compáralas honestamente con lo que compra. En caso de empate, gana la opción simple (KISS).

Un flujo de decisión compacto:

flowchart TD
    A[Tentación de aplicar un patrón] --> B{¿Problema nombrable<br/>sin citar el patrón?}
    B -- No --> Z[No lo apliques:<br/>es solución en busca de problema]
    B -- Sí --> C{¿Eje de cambio real<br/>o ya dolorido?}
    C -- No --> Y[Espera: código simple<br/>+ nota de intención]
    C -- Sí --> D{¿Beneficio > coste<br/>y equipo preparado?}
    D -- No --> Y
    D -- Sí --> E[Aplícalo: nómbralo en el código<br/>y documenta la intención]

Fíjate en la casilla "Espera": no aplicar un patrón hoy no es renunciar a él. Es dejar el código simple y limpio para que, cuando el cambio real llegue, refactorizar hacia el patrón sea barato. De hecho, el camino más sano hacia los patrones es la refactorización guiada por síntomas, y le dedicaremos una lección entera en el módulo 5 (Refactorización Usando Patrones).

Tabla resumen de la balanza

Aspecto Ventaja Coste / riesgo asociado
Comunicación Vocabulario común y preciso del equipo Solo funciona si todos conocen el catálogo
Calidad de la solución Décadas de experiencia destiladas; trampas ya resueltas Falsa seguridad si se aplica el patrón equivocado
Mantenibilidad Cambios localizados (OCP), código testeable (DIP) Más clases e indirección que mantener
Legibilidad Diseño autodocumentado para quien conoce patrones Barrera de entrada para quien no los conoce
Evolución Puntos de extensión preparados para el cambio real Sobreingeniería si el cambio era especulativo (YAGNI)
Relación con frameworks Entiendes y extiendes mejor las herramientas
Rendimiento Indirección con coste marginal (rara vez relevante)

Y la síntesis en una frase: un patrón es una inversión: compra flexibilidad y comunicación pagando complejidad; solo es rentable si esa flexibilidad se usa y esa comunicación se comparte.

Cómo estudiar los próximos módulos con esta balanza en mente

A partir del módulo 2 estudiarás patrones concretos, uno por lección. Para que la balanza de hoy no se quede en teoría, adopta esta disciplina en cada patrón:

  • Lee primero el problema en PideYa e intenta resolverlo tú, de forma simple, antes de ver la solución del patrón. Así sentirás qué añade el patrón y qué añade tu solución ingenua.
  • Al llegar a las consecuencias, no las saltes: son la mitad del patrón. Pregúntate siempre "¿en qué caso NO lo usaría?". Si no sabes responder, no conoces el patrón todavía.
  • En las comparativas de fin de módulo, vuelve a los criterios de esta lección: son el árbitro entre patrones rivales.

Errores Comunes y Consejos

  • La "patternitis" del recién converso. Tras aprender los patrones, todo parece pedir uno. Es una fase normal; la vacuna es el filtro nº 1: si no puedes nombrar el problema sin nombrar el patrón, no hay problema.
  • Medir la calidad de un diseño por cuántos patrones tiene. La métrica es exactamente la contraria: el mejor diseño es el más simple que resuelve el problema y absorbe los cambios reales. Cero patrones puede ser la respuesta correcta.
  • Usar el patrón como excusa para no pensar. "Aquí va un Singleton porque siempre se hace así" no es diseño, es liturgia. Cada aplicación de un patrón debe poder defenderse con el problema y las fuerzas concretas del caso.
  • No nombrar los patrones en el código. Si aplicas un patrón, dilo: PedidoBuilder comunica; GestorPedidos2 esconde. La ventaja del vocabulario se pierde si el patrón queda camuflado.
  • Descartar los patrones por miedo a la sobreingeniería. El péndulo contrario también es un error: código sin abstracción ninguna, con duplicación y if en cadena, es tan caro como el sobrediseñado. La virtud no está en "sin patrones" sino en "los patrones justos".
  • Consejo: en tu próximo diseño, escribe en un comentario o en la descripción del pull request qué cambio futuro concreto justifica cada abstracción que introduces. Si no puedes escribirlo, probablemente sobra.

Ejercicios

Ejercicio 1: pasar un caso por los filtros

El equipo de PideYa debate introducir una jerarquía de estrategias intercambiables para el cálculo del IVA de los pedidos. Datos: PideYa opera solo en España, el IVA de la comida a domicilio no ha cambiado en años, y no hay planes de expansión internacional en el roadmap. Aplica los cinco criterios de la sección 4 y emite un veredicto razonado.

Ejercicio 2: detectar la sobreingeniería

Señala qué elementos de este diseño para el aviso "pedido en reparto" son sobreingeniería, sabiendo que el único requisito es enviar una notificación push al cliente, y propón la versión proporcionada:

public interface CanalAviso { void avisar(Cliente c, String msg); }
public interface FabricaCanales { CanalAviso crearCanal(String tipo); }
public class FabricaCanalesImpl implements FabricaCanales { /* switch de un caso */ }
public class GestorCanales { /* mantiene un registro de fábricas de canales */ }
public class CanalPush implements CanalAviso { /* el único canal existente */ }

Ejercicio 3: argumentar la balanza

Escribe dos párrafos breves: uno defendiendo ante tu equipo el uso de un patrón para las promociones de PideYa (cambian cada mes, las escribe más de un desarrollador), y otro defendiendo NO usar patrón alguno para el email de bienvenida (uno solo, estable desde hace dos años). En cada párrafo cita al menos una ventaja o coste concreto de esta lección.

Soluciones

Solución 1: (1) El problema es nombrable: "calcular el IVA según reglas que podrían variar"; pasa el primer filtro. (2) El eje de cambio es especulativo: un solo país, tipo estable durante años, sin expansión en el roadmap: falla claramente. (3) La alternativa simple (una constante o un método calcularIva(total)) no duele nada hoy. (4–5) Irrelevantes ya, pero el coste (interfaz + implementaciones + inyección) superaría a un beneficio inexistente. Veredicto: no aplicar el patrón; dejar el cálculo en un único punto bien nombrado (eso sí lo exige DRY) para que, si algún día se internacionaliza la plataforma, la refactorización sea local y barata.

Solución 2: sobran FabricaCanales, FabricaCanalesImpl (una fábrica con un switch de un solo caso) y GestorCanales (un registro de fábricas para una fábrica de un canal): tres niveles de indirección sin ninguna variación real que gestionar. Es defendible conservar la interfaz CanalAviso con su única implementación CanalPush inyectada donde se use (coste mínimo, facilita el test), aunque incluso ella es prescindible. Versión proporcionada:

public class ServicioAvisos {
    private final CanalAviso canal;    // hoy, siempre CanalPush

    public ServicioAvisos(CanalAviso canal) { this.canal = canal; }

    public void avisarEnReparto(Pedido pedido) {
        canal.avisar(pedido.getCliente(), "¡Tu pedido está en reparto!");
    }
}

Si mañana aparecen SMS o email como requisito real, añadir implementaciones de CanalAviso será trivial; las fábricas se introducirán solo si la selección del canal se vuelve un problema en sí misma.

Solución 3 (redacciones posibles):

A favor (promociones): «Las promociones cambian cada mes y las toca gente distinta: el eje de variación es real y frecuente. Encapsular cada promoción tras una abstracción común nos da cambios localizados —añadir una promoción será crear una clase, sin tocar ni re-testear las existentes (OCP)— y un vocabulario compartido: en las revisiones diremos "es una promoción nueva" y todos sabremos qué estructura esperar. El coste en clases extra se amortiza en el primer mes.»

En contra (bienvenida): «El email de bienvenida es único y lleva dos años sin cambiar: no hay eje de variación que justifique indirección. Montar abstracciones ahí sería flexibilidad especulativa (YAGNI) y complejidad accidental: más ficheros que abrir para entender un envío de email. Mantengámoslo como una llamada directa, testeable por inyección del servicio de email; si algún día el requisito crece, refactorizar desde código simple será más barato que mantener años una catedral vacía.»

Conclusión

Con esta lección se cierra el módulo introductorio, y con él ya dispones de todo el equipo de base: sabes qué es un patrón (contexto, problema, solución, consecuencias) y qué no lo es, de dónde viene la disciplina (de Alexander al GoF y más allá), qué principios encarnan los patrones (SOLID, DRY, KISS, YAGNI y las dos máximas del GoF), cómo leer sus diagramas (UML con mermaid), cómo se organiza el catálogo (creacionales, estructurales y de comportamiento) y —lo aprendido hoy— cómo pesar sus ventajas contra sus costes para aplicarlos con criterio y no por moda.

Es hora de pasar de los cimientos al primer piso del edificio. En el módulo 2 abordaremos la primera familia del catálogo, la que gobierna el nacimiento de los objetos: cómo crear las piezas de PideYa —pasarelas de pago, notificadores, pedidos complejos— sin acoplar el código a sus clases concretas. Nos vemos en la Introducción a los Patrones Creacionales.

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