Set patrons estructurals després, toca el mateix que vam fer en tancar els creacionals: posar-los sobre la taula junts, que és on es decideix de debò. I en aquesta família la comparativa és més necessària que en cap altra, perquè quatre dels seus membres —Adapter, Decorator, Facade i Proxy— són mecànicament gairebé indistingibles: un objecte davant d'un altre, delegant. Triar malament entre ells no trenca el programa; trenca una cosa més cara: la comunicació del disseny, perquè el nom del patró és una promesa sobre la intenció, i una promesa equivocada despista tothom qui vingui darrere. Taula general, acarament d'embolcalls, guia de decisió, combinacions i el mapa estructural complet de PideYa: som-hi.
Contingut
- Els set, cara a cara
- Els quatre embolcalls: mateixa mecànica, intencions diferents
- Guia de decisió
- Com es combinen entre si
- El mapa estructural de PideYa
- Errors comuns, exercicis i conclusió
Els set, cara a cara
La taula del panorama de la introducció, ara amb el que hem après: símptoma que el dispara i cost que es paga.
| Patró | Intenció en una frase | Símptoma que el dispara | Cost principal |
|---|---|---|---|
| Adapter | Traduir la interfície d'una peça intocable a la que el client espera | Interfícies incompatibles amb codi aliè/llegat | Una classe traductora per adaptee; disciplina de frontera estanca |
| Bridge | Separar abstracció i implementació en dues jerarquies connectades per composició | Subclasses amb nom compost (ConfirmacioPush): dos eixos fosos multiplicant-se |
Disseny a priori; una indirecció; dues jerarquies per mantenir |
| Composite | Tractar uniformement fulles i grups en arbres part-tot | El mateix if (esGrup) repetit a cada operació |
Interfície comuna per consensuar; dilema transparència/seguretat; compte amb els cicles |
| Decorator | Afegir responsabilitats a un objecte embolcallant-lo, combinables en execució | Explosió de subclasses per combinacions d'extres opcionals | Ceba opaca; moltes classes petites; l'ordre de capes importa |
| Facade | Oferir una porta simple davant d'un subsistema complex | La mateixa orquestració copiada en diversos clients | Risc d'engreixar-se; temptació de ficar-hi negoci |
| Flyweight | Compartir l'estat intrínsec de multituds d'objectes | Milers d'instàncies duplicant dades pesants, memòria mesurada al límit | Separar intrínsec/extrínsec complica firmes; exigeix immutabilitat |
| Proxy | Substitut amb la mateixa interfície que controla l'accés al real | Objecte car, sensible, remot o repetidament consultat, amb accés sense control | Indirecció invisible; fidelitat al contracte; caches per invalidar |
Dos eixos transversals per ordenar-los mentalment:
- Quants objectes organitza? Un davant d'un altre: Adapter, Decorator, Proxy. Molts darrere d'un: Facade (un subsistema), Composite (un arbre), Flyweight (una multitud). Dues jerarquies senceres: Bridge.
- Canvia la interfície que veu el client? La canvia: Adapter. La simplifica: Facade. La conserva exactament: Decorator, Proxy, Composite (el grup ofereix la de la fulla). La parteix en dues: Bridge. Li és igual: Flyweight (el seu tema és la memòria, no la interfície).
Els quatre embolcalls: mateixa mecànica, intencions diferents
L'acarament estrella. Els quatre comparteixen el gest —rebre crides adreçades a un altre i decidir què fer-ne— i es distingeixen pel que prometen:
| Aspecte | Adapter | Decorator | Facade | Proxy |
|---|---|---|---|---|
| Interfície resultant | Diferent de la de l'embolcallat (la que el client esperava) | La mateixa de l'embolcallat | Nova i més simple que les del subsistema | La mateixa de l'embolcallat |
| Què promet | Traducció fidel, res més | L'embolcallat més responsabilitats visibles | El cas d'ús comú sense conèixer les tripes | L'embolcallat, amb l'accés vigilat |
| Altera el comportament observable? | No (només l'idioma) | Sí: afegeix, i aquesta és la gràcia | No afegeix regles: coordina les existents | Pot negar-se, posposar o respondre de memòria |
| Embolcalla... | 1 objecte aliè/llegat | 1 objecte propi, sovint ja embolcallat (capes) | N objectes (el subsistema) | 1 objecte propi, normalment el "de debò" |
| Qui el posa allà? | L'integrador, a la frontera | El client o qui compon, apilant a la carta | L'arquitecte, com a porta del mòdul | La infraestructura, sense que el client ho sàpiga |
| A PideYa | AdaptadorPayPal |
ExtraDobleFormatge, NotificadorAmbReintents |
FacanaCheckout |
ProxyImatgePlat, ProxyProteccioGestioComandes |
Quatre preguntes en ordre, que resolen el 90% dels dubtes de classificació:
- La interfície de fora és una altra que la de dins? → Adapter (si és més simple i n'agrupa diversos, → Facade).
- Mateixa interfície: l'embolcall afegeix comportament visible que el client vol i combina? → Decorator.
- Mateixa interfície: l'embolcall decideix sobre l'accés (quan, qui, quantes vegades, on) sense que el client hi participi? → Proxy.
- Continua el dubte (un logging, unes mètriques)? Ets a la frontera Decorator/Proxy que ja vam treballar a la lliçó de Proxy: decideix per qui ho compon i per a què — capa opcional apilada pel desenvolupador, Decorator; control interposat d'ofici per la infraestructura, Proxy — i documenta la decisió. La frontera existeix; fingir que no, confon més.
Guia de decisió
El flux de preguntes del mòdul sencer. Com la guia creacional: orienta el cas típic, i el filtre previ continua vigent — de debò hi ha símptoma, o estem decorant per esport?
flowchart TD
A[Problema en compondre<br/>o organitzar objectes] --> B{Es de MEMORIA?<br/>milers d'objectes, dades repetides,<br/>profiler en vermell}
B -- Si --> FW[Flyweight<br/>intrinsec compartit + fabrica]
B -- No --> C{L'estructura del domini<br/>es un ARBRE part-tot?}
C -- Si --> CP[Composite<br/>fulles i grups uniformes]
C -- No --> D{Una jerarquia creix per<br/>PRODUCTE de dos eixos<br/>independents?}
D -- Si --> BR[Bridge<br/>abstraccio × implementacio]
D -- No --> E{El problema es en<br/>UN objecte al qual poso<br/>alguna cosa al davant?}
E -- No --> F{Molts clients repeteixen<br/>l'orquestracio d'un subsistema?}
F -- Si --> FC[Facade<br/>porta d'alt nivell]
F -- No --> Z[Potser no es un problema<br/>estructural: revisa creacionals<br/>o espera al modul 4]
E -- Si --> G{La seva interficie NO es<br/>la que necessito?}
G -- Si --> AD[Adapter<br/>traduir a la frontera]
G -- No --> H{Vull AFEGIR comportament<br/>combinable i visible?}
H -- Si --> DC[Decorator<br/>capes apilables]
H -- No --> PX[Proxy<br/>controlar l'acces:<br/>virtual, proteccio, cache, remot]
Consells d'ús, com sempre: les respostes poden ser diverses (un subsistema amb façana pot contenir un composite amb cache darrere d'un proxy); la guia s'aplica per decisió de disseny, no per sistema; i si cap branca no encaixa, la sortida "potser no és estructural" és una resposta legítima — els problemes de comunicació i repartiment de responsabilitats en execució pertanyen al mòdul que ve.
Com es combinen entre si
Com els creacionals, els estructurals treballen en colla. Les combinacions que ja vas veure o olorar a PideYa:
- Composite + Decorator: comparteixen interfície Component per disseny; un decorador pot embolcallar qualsevol node de l'arbre. Els extres (
ExtraDobleFormatge) decoren plats que viuen a la carta Composite; tots dos són, per al client,Producte/ComponentCarta. - Composite + Flyweight: les fulles repetides d'un arbre enorme es comparteixen com a flyweights (el GoF ho assenyala expressament); a PideYa, si cada restaurant d'una franquícia repeteix la mateixa carta base, els
Platcompartits en són candidats. - Proxy + Composite:
ProxyCacheCatalegretorna arbres de carta complets: el proxy controla l'accés; el composite estructura allò accedit. - Facade sobre tots:
FacanaCheckoutcoordina un subsistema on ja treballen l'Abstract Factory de mercats, el Builder deComanda, adaptadors de passarel·les i notificadors decorats. La façana no competeix amb ells: els amaga. - Adapter dins de Bridge: un implementor concret (
CanalWhatsApp) pot ser internament un adaptador de l'SDK del proveïdor. El pont dóna la forma; l'adaptador, la frontera. - Decorator/Proxy apilats entre si: logging per fora de reintents, protecció per dins de logging... L'ordre de capes és semàntica (què es registra, què es reintenta): ho vas comprovar als exercicis de totes dues lliçons.
- Creacionals al servei d'estructurals: les fàbriques munten les estructures — decideixen si lliuren l'objecte real o el seu proxy, componen la pila estàndard de decoradors, trien l'adaptador del mercat. La frase del mòdul 2 continua viva: cada patró governa una capa de la decisió.
El mapa estructural de PideYa
El repàs final del sistema, com vam tancar el mòdul creacional: què va quedar instal·lat, on i per què — amb l'última fila de sempre, la més important.
| Part de PideYa | Solució estructural | Per què aquesta i no una altra |
|---|---|---|
| Cobraments amb l'SDK heretat de PayPal | Adapter (AdaptadorPayPal implements PassarellaPagament) |
Interfície aliena i intocable que havia de semblar una passarel·la més; tota la duana en un punt |
| Catàleg de l'agregador extern | Adapter (AdaptadorAgregador) |
Mateix símptoma, una altra frontera: model de tercers traduït al nostre |
| Notificacions: tipus × canals | Bridge (Notificacio ⇄ CanalEnviament) |
Dos eixos independents creixent per producte (9 classes) → creixement additiu (3+3) |
| La carta del restaurant | Composite (ComponentCarta, Plat, SeccioCarta), variant segura |
Arbre part-tot de profunditat lliure amb operacions uniformes i recursives |
| Menús i menús niats | Composite (Menu, preu recursiu amb descompte) |
El grup també es ven; allMatch davant d'anyMatch segons el negoci |
| Extres dels plats | Decorator (ExtraPlat: doble formatge, sense gluten, ració gran) |
Combinatòria opcional decidida per cada client en execució; 3 classes cobreixen 8 combinacions |
| Reintents i traces de notificadors | Decorator tècnic (NotificadorAmbReintents, NotificadorAmbLogging) |
Responsabilitat transversal, opcional i componible sense tocar els canals |
| Flux de confirmació de comanda | Facade (FacanaCheckout) |
Orquestració delicada copiada en quatre clients → escrita una vegada darrere d'una porta simple |
| Seguiment de la comanda a les apps | Facade (FacanaSeguiment) |
Mateix símptoma a escala menor; tipus propis de frontera |
| Mapa en temps real | Flyweight (IconaMarcador + FabricaIcones) |
13.000 marcadors repetint ~25 combinacions d'icona: de 400 MB a menys d'1 |
| Fotos dels plats | Proxy virtual (ProxyImatgePlat) |
Objecte car i d'ús escàs: es paga només el que es mira |
| Permisos del panell intern | Proxy de protecció (ProxyProteccioGestioComandes) |
El qui concentrat en un punt auditable; el servei real, net de seguretat |
| Consultes de carta massives | Proxy de cache (ProxyCacheCataleg) |
Resposta cara i estable, demanada milers de vegades; invalidació dissenyada alhora |
| Traces transversals multi-interfície | Proxy dinàmic (ManipuladorLogging + java.lang.reflect.Proxy) |
Un sol handler per a totes les interfícies; el mecanisme dels frameworks |
| Comandes, cistelles, línies, adreces... | Cap | Objectes en quantitats normals, interfícies que encaixen, sense eixos multiplicant-se: qualsevol embolcall aquí seria soroll |
Aquest és el criteri de maduresa que venim repetint des de la balança: no quants patrons té el sistema, sinó que cadascun sigui on el seu símptoma el va justificar — i que la resta del codi continuï sent simple.
Errors Comuns i Consells
- Anomenar per mecànica, no per intenció. Dir-ne "proxy" d'un adaptador o "decorador" d'una façana compila igual, però menteix al lector sobre la promesa (tradueix? afegeix? controla?). En aquesta família, el nom del patró és documentació de primera classe: gasta'l bé.
- Embolcallar per costum. Després d'aquest mòdul, la temptació és posar capes a tot. Cada embolcall és una indirecció que algú depurarà; sense símptoma (interfície que no encaixa, responsabilitat opcional, accés per controlar), la millor estructura és cap.
- Resoldre amb herència el que aquest mòdul resol amb composició. La subclasse
MargaritaSenseGlutenoConfirmacioPushsempre serà a mà i sempre semblarà més ràpida. Recorda les dues explosions (Decorator i Bridge les curen) abans d'heretar la pròxima variant. - Triar Bridge quan tocava Adapter, o a l'inrevés. Si les peces ja existeixen i no encaixen: Adapter, i a una altra cosa. Si les jerarquies les dissenyes tu i creixeran per dos eixos: Bridge. Dissenyar "ponts" cap a SDKs aliens o "adaptar" jerarquies pròpies són les dues disfresses del mateix despiste.
- Façana com a amagatall. Si darrere de la façana el subsistema és un nus, el nus continua creixent — ara sense que ningú no el miri. La façana corona un subsistema sa; no el substitueix.
- Consell: repeteix aquí l'exercici del mapa que vas fer amb els creacionals: llista cada frontera, cada jerarquia i cada multitud del teu sistema, i anota quin estructural (o quina absència) la governa i per què. Les files sense justificació són les teves candidates a simplificar; les fronteres sense adaptador i les orquestracions copiades, les teves candidates a millorar.
Exercicis
Exercici 1: diagnòstic exprés
Per a cada situació nova a PideYa, tria el patró estructural (o cap) i justifica-ho en una frase amb el seu discriminant:
- El servei de facturació d'un partner exigeix rebre les comandes en el seu format EDI, molt diferent del nostre model
Comanda. - Els cupons apliquen recàrrecs/descomptes apilables sobre el preu d'una comanda: enviament gratis, -10% primera compra, +0,50 € per hora punta, combinables segons campanya.
- Les zones de repartiment s'organitzen en districtes que contenen barris que contenen carrers, i cal saber si una adreça cau en una zona amb recàrrec, a qualsevol nivell.
- El nou widget "demana amb un toc" per al mòbil ha de repetir l'última comanda: avui exigeix cridar cinc serveis en ordre.
- Cadascun dels 2 milions de clients desa el seu objecte
PreferenciesNotificacio, i el 97% té exactament la configuració per defecte. - Volem que el servei de geocodificació només s'instanciï (carrega un índex de 2 GB) si alguna comanda del dia necessita resoldre una adreça nova.
Exercici 2: l'acarament en codi
Sense context, un company troba aquesta classe i pregunta quin patró és. Què li contestes i quina informació addicional demanaries per decidir del tot?
public class ServeiRepartimentVigilat implements ServeiRepartiment {
private final ServeiRepartiment intern;
private final Rellotge rellotge;
@Override
public AssignacioRepartiment assignar(Comanda comanda) {
long inici = rellotge.ara();
AssignacioRepartiment a = intern.assignar(comanda);
Metriques.registrar("assignar", rellotge.ara() - inici);
return a;
}
}Exercici 3: combinar amb seny
L'equip de partners vol exposar a tercers la consulta de cartes: API pública senzilla, sense revelar el model intern, amb respostes ràpides encara que el catàleg estigui sota càrrega, i sense que un partner sense contracte actiu pugui consultar. Proposa la combinació de patrons estructurals (mínims) i l'ordre en què es travessen en una petició.
Solucions
Solució 1:
- Adapter: format aliè i intocable a la frontera; un
AdaptadorFacturacioEditradueixComanda→ EDI i res més. - Decorator: recàrrecs/descomptes opcionals, apilables i amb ordre significatiu sobre una interfície de preu — la ceba dels extres, en el domini dels cupons.
- Composite: part-tot recursiu (districte ⊃ barri ⊃ carrer) amb una operació uniforme (
teRecarrec(adreca)), resposta per fulles i propagada per grups. - Facade: orquestració de diversos subsistemes repetida des d'un client més; una
FacanaComandaRapida(que per dins reutilitzarà el Prototype de "repetir comanda" del mòdul 2). - Flyweight: multitud (2M) amb estat massivament repetit (97% idèntic i immutable): una instància compartida de les preferències per defecte i objectes propis només per a qui personalitza.
- Proxy virtual: objecte caríssim d'instanciar i possiblement no usat; el proxy materialitza el geocodificador al primer ús real.
Solució 2: la resposta curta: "per mecànica és un embolcall amb la mateixa interfície; per intenció, mesurar crides és a la frontera Decorator/Proxy". Informació per decidir: qui el compon i amb quina obligatorietat. Si és la infraestructura qui l'interposa sempre en producció, sense que cap client no el triï (control d'ofici): digues-ne proxy (de mètriques/logging). Si és una capa opcional que cada punt d'ús apila o no, combinant-la amb d'altres (reintents, traces): digues-ne decorador tècnic. També ajuda saber si existeix una família d'embolcalls apilables (fa olor de Decorator) o si aquest és únic i fix davant del servei real (fa olor de Proxy). L'important —digues-li també això— és que la classe està bé: el dubte és d'etiqueta, no de disseny.
Solució 3: tres peces, de fora endins: (1) Facade ApiPublicaCartes: superfície mínima per a partners, amb tipus propis de frontera (res del model intern; l'acarament va ensenyar que interfície nova i més simple sobre un subsistema = façana). (2) Proxy de protecció sobre el servei de catàleg: verifica el contracte actiu del partner i denega registrant (el qui). (3) Proxy de cache (ProxyCacheCataleg, reutilitzat): respostes estables servides de memòria (el quantes vegades). Ordre d'una petició: façana → protecció → cache → catàleg real, que retorna l'arbre Composite de la carta (quarta peça, ja existent, gratis). Protecció abans que cache: un partner morós no ha ni d'escalfar la cache — l'ordre d'embolcalls torna a ser semàntica.
Conclusió
Ja no tens set patrons solts sinó un sistema de decisió: la taula d'intencions i costos, els dos eixos (quants objectes?, què passa amb la interfície?), l'acarament dels quatre embolcalls amb les seves quatre preguntes, el flowchart per al cas típic i les combinacions que apareixen soles quan el disseny va bé. I tens el mapa de PideYa com a demostració de la tesi del curs sencer: cada patró instal·lat on un símptoma concret el va justificar, cap on no — amb la fila "Cap" defensada amb el mateix orgull que les altres.
Amb això, dos terços del catàleg GoF són a la teva caixa d'eines: els creacionals van resoldre el naixement dels objectes; els estructurals, la seva anatomia — com es connecten, embolcallen i organitzen. Queda la tercera pregunta, la més dinàmica de totes: amb els objectes ja creats i ben connectats, com col·laboren en execució? Qui avisa qui quan la comanda canvia d'estat, com es desfà una acció, com recorre la cuina una cua de comandes sense conèixer-ne l'estructura, on viu l'algorisme que decideix el repartiment? Aquesta és la família més nombrosa del catàleg —onze patrons de comportament— i PideYa és plena de converses esperant-los. Ens veiem a la Introducció als Patrons de Comportament.
Curs de Patrons de Disseny de Programari
Mòdul 1: Introducció als Patrons de Disseny
- Què són els Patrons de Disseny?
- Història i Origen dels Patrons de Disseny
- Principis de Disseny: SOLID i Altres Fonaments
- UML Essencial per Entendre Patrons
- Classificació dels Patrons de Disseny
- Avantatges i Desavantatges d'Usar Patrons de Disseny
Mòdul 2: Patrons Creacionals
- Introducció als Patrons Creacionals
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
- Comparativa i Elecció de Patrons Creacionals
Mòdul 3: Patrons Estructurals
- Introducció als Patrons Estructurals
- Adapter
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy
- Comparativa i Elecció de Patrons Estructurals
Mòdul 4: Patrons de Comportament
- Introducció als Patrons de Comportament
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
- Comparativa i Elecció de Patrons de Comportament
Mòdul 5: Aplicació de Patrons de Disseny
- Com Seleccionar el Patró Adequat
- Exemples Pràctics d'Ús de Patrons
- Patrons de Disseny en Projectes Reals
- Refactorització Usant Patrons de Disseny
- Antipatrons: Quan els Patrons es Tornen un Problema
Mòdul 6: Patrons de Disseny Avançats
- Patrons de Disseny en Arquitectures Modernes
- Patrons de Disseny en Microserveis
- Patrons de Disseny en Sistemes Distribuïts
- Patrons de Concurrència
- Patrons de Disseny en Desenvolupament Àgil
