Siete patrones estructurales después, toca lo mismo que hicimos al cerrar los creacionales: ponerlos sobre la mesa juntos, que es donde se decide de verdad. Y en esta familia la comparativa es más necesaria que en ninguna otra, porque cuatro de sus miembros —Adapter, Decorator, Facade y Proxy— son mecánicamente casi indistinguibles: un objeto delante de otro, delegando. Elegir mal entre ellos no rompe el programa; rompe algo más caro: la comunicación del diseño, porque el nombre del patrón es una promesa sobre la intención, y una promesa equivocada despista a todo el que venga detrás. Tabla general, careo de envoltorios, guía de decisión, combinaciones y el mapa estructural completo de PideYa: vamos a ello.

Contenido

  1. Los siete, frente a frente
  2. Los cuatro envoltorios: misma mecánica, intenciones distintas
  3. Guía de decisión
  4. Cómo se combinan entre sí
  5. El mapa estructural de PideYa
  6. Errores comunes, ejercicios y conclusión

Los siete, frente a frente

La tabla del panorama de la introducción, ahora con lo aprendido: síntoma que lo dispara y coste que se paga.

Patrón Intención en una frase Síntoma que lo dispara Coste principal
Adapter Traducir la interfaz de una pieza intocable a la que el cliente espera Interfaces incompatibles con código ajeno/legado Una clase traductora por adaptee; disciplina de frontera estanca
Bridge Separar abstracción e implementación en dos jerarquías conectadas por composición Subclases con nombre compuesto (ConfirmacionPush): dos ejes fundidos multiplicándose Diseño a priori; una indirección; dos jerarquías que mantener
Composite Tratar uniformemente hojas y grupos en árboles parte-todo El mismo if (esGrupo) repetido en cada operación Interfaz común que consensuar; dilema transparencia/seguridad; cuidado con ciclos
Decorator Añadir responsabilidades a un objeto envolviéndolo, combinables en ejecución Explosión de subclases por combinaciones de extras opcionales Cebolla opaca; muchas clases pequeñas; el orden de capas importa
Facade Ofrecer una puerta simple ante un subsistema complejo La misma orquestación copiada en varios clientes Riesgo de engordar; tentación de meterle negocio
Flyweight Compartir el estado intrínseco de multitudes de objetos Miles de instancias duplicando datos pesados, memoria medida al límite Separar intrínseco/extrínseco complica firmas; exige inmutabilidad
Proxy Sustituto con la misma interfaz que controla el acceso al real Objeto caro, sensible, remoto o repetidamente consultado, con acceso sin control Indirección invisible; fidelidad al contrato; cachés que invalidar

Dos ejes transversales para ordenarlos mentalmente:

  • ¿Cuántos objetos organiza? Uno frente a otro: Adapter, Decorator, Proxy. Muchos tras uno: Facade (un subsistema), Composite (un árbol), Flyweight (una multitud). Dos jerarquías enteras: Bridge.
  • ¿Cambia la interfaz que ve el cliente? La cambia: Adapter. La simplifica: Facade. La conserva exactamente: Decorator, Proxy, Composite (el grupo ofrece la de la hoja). La parte en dos: Bridge. Le da igual: Flyweight (su tema es la memoria, no la interfaz).

Los cuatro envoltorios: misma mecánica, intenciones distintas

El careo estrella. Los cuatro comparten el gesto —recibir llamadas dirigidas a otro y decidir qué hacer con ellas— y se distinguen por lo que prometen:

Aspecto Adapter Decorator Facade Proxy
Interfaz resultante Distinta de la del envuelto (la que el cliente esperaba) La misma del envuelto Nueva y más simple que las del subsistema La misma del envuelto
Qué promete Traducción fiel, nada más El envuelto más responsabilidades visibles El caso de uso común sin conocer las tripas El envuelto, con el acceso vigilado
¿Altera el comportamiento observable? No (solo el idioma) Sí: añade, y esa es la gracia No añade reglas: coordina las existentes Puede negarse, posponer o responder de memoria
Envuelve a... 1 objeto ajeno/legado 1 objeto propio, a menudo ya envuelto (capas) N objetos (el subsistema) 1 objeto propio, normalmente el "de verdad"
¿Quién lo pone ahí? El integrador, en la frontera El cliente o quien compone, apilando a la carta El arquitecto, como puerta del módulo La infraestructura, sin que el cliente lo sepa
En PideYa AdaptadorPayPal ExtraDobleQueso, NotificadorConReintentos FachadaCheckout ProxyImagenPlato, ProxyProteccionGestionPedidos

Cuatro preguntas en orden, que resuelven el 90% de las dudas de clasificación:

  1. ¿La interfaz de fuera es otra que la de dentro? → Adapter (si es más simple y agrupa varios, → Facade).
  2. Misma interfaz: ¿el envoltorio añade comportamiento visible que el cliente quiere y combina? → Decorator.
  3. Misma interfaz: ¿el envoltorio decide sobre el acceso (cuándo, quién, cuántas veces, dónde) sin que el cliente participe? → Proxy.
  4. ¿Sigue la duda (un logging, unas métricas)? Estás en la frontera Decorator/Proxy que ya trabajamos en la lección de Proxy: decide por quién lo compone y para qué — capa opcional apilada por el desarrollador, Decorator; control interpuesto de oficio por la infraestructura, Proxy — y documenta la decisión. La frontera existe; fingir que no, confunde más.

Guía de decisión

El flujo de preguntas del módulo entero. Como la guía creacional: orienta el caso típico, y el filtro previo sigue vigente — ¿de verdad hay síntoma, o estamos decorando por deporte?

flowchart TD
    A[Problema al componer<br/>u organizar objetos] --> B{¿Es de MEMORIA?<br/>miles de objetos, datos repetidos,<br/>profiler en rojo}
    B -- Sí --> FW[Flyweight<br/>intrínseco compartido + fábrica]
    B -- No --> C{¿La estructura del dominio<br/>es un ÁRBOL parte-todo?}
    C -- Sí --> CP[Composite<br/>hojas y grupos uniformes]
    C -- No --> D{¿Una jerarquía crece por<br/>PRODUCTO de dos ejes<br/>independientes?}
    D -- Sí --> BR[Bridge<br/>abstracción × implementación]
    D -- No --> E{¿El problema está en<br/>UN objeto al que pongo<br/>algo delante?}
    E -- No --> F{¿Muchos clientes repiten la<br/>orquestación de un subsistema?}
    F -- Sí --> FC[Facade<br/>puerta de alto nivel]
    F -- No --> Z[Quizá no es un problema<br/>estructural: revisa creacionales<br/>o espera al módulo 4]
    E -- Sí --> G{¿Su interfaz NO es<br/>la que necesito?}
    G -- Sí --> AD[Adapter<br/>traducir en la frontera]
    G -- No --> H{¿Quiero AÑADIR comportamiento<br/>combinable y visible?}
    H -- Sí --> DC[Decorator<br/>capas apilables]
    H -- No --> PX[Proxy<br/>controlar el acceso:<br/>virtual, protección, caché, remoto]

Consejos de uso, como siempre: las respuestas pueden ser varias (un subsistema con fachada puede contener un composite cacheado por un proxy); la guía se aplica por decisión de diseño, no por sistema; y si ninguna rama encaja, la salida "quizá no es estructural" es una respuesta legítima — los problemas de comunicación y reparto de responsabilidades en ejecución pertenecen al módulo que viene.

Cómo se combinan entre sí

Como los creacionales, los estructurales trabajan en cuadrilla. Las combinaciones que ya viste u olfateaste en PideYa:

  • Composite + Decorator: comparten interfaz Component por diseño; un decorador puede envolver cualquier nodo del árbol. Los extras (ExtraDobleQueso) decoran platos que viven en la carta Composite; ambos son, para el cliente, Producto/ComponenteCarta.
  • Composite + Flyweight: las hojas repetidas de un árbol enorme se comparten como flyweights (el GoF lo señala expresamente); en PideYa, si cada restaurante de una franquicia repite la misma carta base, los Plato compartidos son candidatos.
  • Proxy + Composite: ProxyCacheCatalogo devuelve árboles de carta completos: el proxy controla el acceso; el composite estructura lo accedido.
  • Facade sobre todos: FachadaCheckout coordina un subsistema donde ya trabajan la Abstract Factory de mercados, el Builder de Pedido, adaptadores de pasarelas y notificadores decorados. La fachada no compite con ellos: los esconde.
  • Adapter dentro de Bridge: un implementor concreto (CanalWhatsApp) puede ser internamente un adaptador del SDK del proveedor. El puente da la forma; el adaptador, la frontera.
  • Decorator/Proxy apilados entre sí: logging por fuera de reintentos, protección por dentro de logging... El orden de capas es semántica (qué se registra, qué se reintenta): lo comprobaste en los ejercicios de ambas lecciones.
  • Creacionales al servicio de estructurales: las fábricas montan las estructuras — deciden si entregan el objeto real o su proxy, componen la pila estándar de decoradores, eligen el adaptador del mercado. La frase del módulo 2 sigue viva: cada patrón gobierna una capa de la decisión.

El mapa estructural de PideYa

El repaso final del sistema, como cerramos el módulo creacional: qué quedó instalado, dónde y por qué — con la última fila de siempre, la más importante.

Parte de PideYa Solución estructural Por qué esa y no otra
Cobros con el SDK heredado de PayPal Adapter (AdaptadorPayPal implements PasarelaPago) Interfaz ajena e intocable que debía parecer una pasarela más; toda la aduana en un punto
Catálogo del agregador externo Adapter (AdaptadorAgregador) Mismo síntoma, otra frontera: modelo de terceros traducido al nuestro
Notificaciones: tipos × canales Bridge (NotificacionCanalEnvio) Dos ejes independientes creciendo por producto (9 clases) → crecimiento aditivo (3+3)
La carta del restaurante Composite (ComponenteCarta, Plato, SeccionCarta), variante segura Árbol parte-todo de profundidad libre con operaciones uniformes y recursivas
Menús y menús anidados Composite (Menu, precio recursivo con descuento) El grupo también se vende; allMatch frente a anyMatch según el negocio
Extras de los platos Decorator (ExtraPlato: doble queso, sin gluten, ración grande) Combinatoria opcional decidida por cada cliente en ejecución; 3 clases cubren 8 combinaciones
Reintentos y trazas de notificadores Decorator técnico (NotificadorConReintentos, NotificadorConLogging) Responsabilidad transversal, opcional y componible sin tocar los canales
Flujo de confirmación de pedido Facade (FachadaCheckout) Orquestación delicada copiada en cuatro clientes → escrita una vez tras una puerta simple
Seguimiento del pedido en las apps Facade (FachadaSeguimiento) Mismo síntoma a escala menor; tipos propios de frontera
Mapa en tiempo real Flyweight (IconoMarcador + FabricaIconos) 13.000 marcadores repitiendo ~25 combinaciones de icono: de 400 MB a menos de 1
Fotos de los platos Proxy virtual (ProxyImagenPlato) Objeto caro y de uso escaso: se paga solo lo que se mira
Permisos del panel interno Proxy de protección (ProxyProteccionGestionPedidos) El quién concentrado en un punto auditable; el servicio real, limpio de seguridad
Consultas de carta masivas Proxy de caché (ProxyCacheCatalogo) Respuesta cara y estable, pedida miles de veces; invalidación diseñada a la vez
Trazas transversales multi-interfaz Proxy dinámico (ManejadorLogging + java.lang.reflect.Proxy) Un solo handler para todas las interfaces; el mecanismo de los frameworks
Pedidos, carritos, líneas, direcciones... Ninguno Objetos en cantidades normales, interfaces que encajan, sin ejes multiplicándose: cualquier envoltorio aquí sería ruido

Ese es el criterio de madurez que venimos repitiendo desde la balanza: no cuántos patrones tiene el sistema, sino que cada uno esté donde su síntoma lo justificó — y que el resto del código siga siendo simple.

Errores Comunes y Consejos

  • Nombrar por mecánica, no por intención. Llamar "proxy" a un adaptador o "decorador" a una fachada compila igual, pero miente al lector sobre la promesa (¿traduce? ¿añade? ¿controla?). En esta familia, el nombre del patrón es documentación de primera clase: gástalo bien.
  • Envolver por costumbre. Tras este módulo, la tentación es poner capas a todo. Cada envoltorio es una indirección que alguien depurará; sin síntoma (interfaz que no encaja, responsabilidad opcional, acceso que controlar), la mejor estructura es ninguna.
  • Resolver con herencia lo que este módulo resuelve con composición. La subclase MargaritaSinGluten o ConfirmacionPush siempre estará a mano y siempre parecerá más rápida. Recuerda las dos explosiones (Decorator y Bridge las curan) antes de heredar la próxima variante.
  • Elegir Bridge cuando tocaba Adapter, o al revés. Si las piezas ya existen y no encajan: Adapter, y a otra cosa. Si las jerarquías las diseñas tú y van a crecer por dos ejes: Bridge. Diseñar "puentes" hacia SDKs ajenos o "adaptar" jerarquías propias son los dos disfraces del mismo despiste.
  • Fachada como escondite. Si detrás de la fachada el subsistema es un nudo, el nudo sigue creciendo — ahora sin que nadie lo mire. La fachada corona un subsistema sano; no lo sustituye.
  • Consejo: repite aquí el ejercicio del mapa que hiciste con los creacionales: lista cada frontera, cada jerarquía y cada multitud de tu sistema, y anota qué estructural (o qué ausencia) la gobierna y por qué. Las filas sin justificación son tus candidatas a simplificar; las fronteras sin adaptador y las orquestaciones copiadas, tus candidatas a mejorar.

Ejercicios

Ejercicio 1: diagnóstico exprés

Para cada situación nueva en PideYa, elige el patrón estructural (o ninguno) y justifícalo en una frase con su discriminante:

  1. El servicio de facturación de un partner exige recibir los pedidos en su formato EDI, muy distinto de nuestro modelo Pedido.
  2. Los cupones aplican recargos/descuentos apilables sobre el precio de un pedido: envío gratis, -10% primera compra, +0,50 € por hora punta, combinables según campaña.
  3. Las zonas de reparto se organizan en distritos que contienen barrios que contienen calles, y hay que saber si una dirección cae en una zona con recargo, a cualquier nivel.
  4. El nuevo widget "pide en un toque" para el móvil debe repetir el último pedido: hoy exige llamar a cinco servicios en orden.
  5. Cada uno de los 2 millones de clientes guarda su objeto PreferenciasNotificacion, y el 97% tiene exactamente la configuración por defecto.
  6. Queremos que el servicio de geocodificación solo se instancie (carga un índice de 2 GB) si algún pedido del día necesita resolver una dirección nueva.

Ejercicio 2: el careo en código

Sin contexto, un compañero encuentra esta clase y pregunta qué patrón es. ¿Qué le contestas y qué información adicional pedirías para decidir del todo?

public class ServicioRepartoVigilado implements ServicioReparto {
    private final ServicioReparto interno;
    private final Reloj reloj;

    @Override
    public AsignacionReparto asignar(Pedido pedido) {
        long inicio = reloj.ahora();
        AsignacionReparto a = interno.asignar(pedido);
        Metricas.registrar("asignar", reloj.ahora() - inicio);
        return a;
    }
}

Ejercicio 3: combinar con cabeza

El equipo de partners quiere exponer a terceros la consulta de cartas: API pública sencilla, sin revelar el modelo interno, con respuestas rápidas aunque el catálogo esté bajo carga, y sin que un partner sin contrato activo pueda consultar. Propón la combinación de patrones estructurales (mínimos) y el orden en que se atraviesan en una petición.

Soluciones

Solución 1:

  1. Adapter: formato ajeno e intocable en la frontera; un AdaptadorFacturacionEdi traduce Pedido → EDI y nada más.
  2. Decorator: recargos/descuentos opcionales, apilables y con orden significativo sobre una interfaz de precio — la cebolla de los extras, en el dominio de los cupones.
  3. Composite: parte-todo recursivo (distrito ⊃ barrio ⊃ calle) con una operación uniforme (tieneRecargo(direccion)), respondida por hojas y propagada por grupos.
  4. Facade: orquestación de varios subsistemas repetida desde un cliente más; una FachadaPedidoRapido (que por dentro reutilizará el Prototype de "repetir pedido" del módulo 2).
  5. Flyweight: multitud (2M) con estado masivamente repetido (97% idéntico e inmutable): una instancia compartida de las preferencias por defecto y objetos propios solo para quien personaliza.
  6. Proxy virtual: objeto carísimo de instanciar y posiblemente no usado; el proxy materializa el geocodificador al primer uso real.

Solución 2: la respuesta corta: "por mecánica es un envoltorio con la misma interfaz; por intención, medir llamadas está en la frontera Decorator/Proxy". Información para decidir: quién lo compone y con qué obligatoriedad. Si es la infraestructura quien lo interpone siempre en producción, sin que ningún cliente lo elija (control de oficio): llámalo proxy (de métricas/logging). Si es una capa opcional que cada punto de uso apila o no, combinándola con otras (reintentos, trazas): llámalo decorador técnico. También ayuda saber si existe una familia de envoltorios apilables (huele a Decorator) o si este es único y fijo delante del servicio real (huele a Proxy). Lo importante —dile también esto— es que la clase está bien: la duda es de etiqueta, no de diseño.

Solución 3: tres piezas, de fuera adentro: (1) Facade ApiPublicaCartas: superficie mínima para partners, con tipos propios de frontera (nada del modelo interno; el careo enseñó que interfaz nueva y más simple sobre un subsistema = fachada). (2) Proxy de protección sobre el servicio de catálogo: verifica el contrato activo del partner y deniega registrando (el quién). (3) Proxy de caché (ProxyCacheCatalogo, reutilizado): respuestas estables servidas de memoria (el cuántas veces). Orden de una petición: fachada → protección → caché → catálogo real, que devuelve el árbol Composite de la carta (cuarta pieza, ya existente, gratis). Protección antes que caché: un partner moroso no debe ni calentar la caché — el orden de envoltorios vuelve a ser semántica.

Conclusión

Ya no tienes siete patrones sueltos sino un sistema de decisión: la tabla de intenciones y costes, los dos ejes (¿cuántos objetos?, ¿qué pasa con la interfaz?), el careo de los cuatro envoltorios con sus cuatro preguntas, el flowchart para el caso típico y las combinaciones que aparecen solas cuando el diseño va bien. Y tienes el mapa de PideYa como demostración de la tesis del curso entero: cada patrón instalado donde un síntoma concreto lo justificó, ninguno donde no — con la fila "Ninguno" defendida con el mismo orgullo que las demás.

Con esto, dos tercios del catálogo GoF están en tu caja de herramientas: los creacionales resolvieron el nacimiento de los objetos; los estructurales, su anatomía — cómo se conectan, envuelven y organizan. Queda la tercera pregunta, la más dinámica de todas: con los objetos ya creados y bien conectados, ¿cómo colaboran en ejecución? ¿Quién avisa a quién cuando el pedido cambia de estado, cómo se deshace una acción, cómo recorre cocina una cola de comandas sin conocer su estructura, dónde vive el algoritmo que decide el reparto? Esa es la familia más numerosa del catálogo —once patrones de comportamiento— y PideYa está llena de conversaciones esperándolos. Nos vemos en la Introducción a los Patrones de Comportamiento.

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