El catàleg ja és complet: 23 patrons, tres famílies, i PideYa sencera com a demostració. Però els problemes reals no arriben etiquetats — cap tiquet de Jira no diu "aplicar Strategy aquí". Arriben com a símptomes: un switch que creix, una classe que ningú no vol tocar, un requisit que obliga a canviar cinc fitxers. Aquesta lliçó ensenya el mètode per anar del símptoma al patró (o a cap patró, que també és una elecció): anomenar el problema abans que la solució, analitzar-ne les forces, fer les preguntes de diagnòstic correctes i validar la resposta abans d'escriure una sola línia. És la primera lliçó de l'ofici: la diferència entre tenir les eines i ser bon fuster.
Contingut
- Primer el problema, després el patró
- El catàleg de forces: què varia i què ha de romandre estable
- Preguntes de diagnòstic per família
- L'arbre de decisió global del catàleg GoF
- Tres casos de PideYa resolts amb el mètode
- "Espera fins que faci mal": el patró que no es tria per endavant
- Exercicis i conclusió
Primer el problema, després el patró
L'error més comú en aplicar patrons no és triar malament entre Strategy i State: és començar pel patró. Qui pregunta "on puc encabir un Visitor?" ja ha perdut — té una solució buscant problema. El mètode correcte inverteix l'ordre:
- Descriu el problema sense anomenar cap patró. En una o dues frases, en llenguatge de negoci i de codi: "cada cop que màrqueting afegeix un tipus de cupó, toquem la classe de checkout i se'ns escapa algun cas".
- Identifica les forces. Què canvia sovint? Què ha de quedar intacte? Qui no ha de conèixer qui? (apartat següent).
- Classifica el problema per família: va de crear objectes, de compondre estructures o de coordinar conducta?
- Aplica les preguntes de diagnòstic d'aquesta família i arriba a un o dos candidats.
- Valida contra la intenció i l'acarament. Llegeix la secció "aplicabilitat" del candidat i el seu acarament amb el patró veí (les comparatives existeixen per a això). Si la intenció del patró no coincideix amb la teva frase del pas 1, torna a començar.
- Passa els cinc filtres de la balança: problema anomenable, eix de canvi real, dolor present, equip preparat, benefici més gran que el cost.
Fixa-t'hi: el patró apareix al pas 4, no a l'1. Tot el que ve abans és anàlisi del problema — i és la part que distingeix el professional.
El catàleg de forces: què varia i què ha de romandre estable
Els GoF ho van escriure al pròleg i és la frase més útil del llibre: "encapsula allò que varia". Cada patró protegeix una zona estable d'una zona variable concreta. Identificar l'eix de variació del teu problema és identificar mitja resposta:
| Allò que varia (o que vols poder variar) | Allò que ha de romandre estable | Família / candidats |
|---|---|---|
| La classe concreta que s'instancia | El codi que la usa | Factory Method, Abstract Factory |
| Com es construeix un objecte complex | La seva representacio final i les invariants | Builder |
| El punt de partida d'un objecte nou | El procés que el consumeix | Prototype |
| La interfície que ofereix un tercer | La interfície que el teu codi espera | Adapter |
| Dues dimensions independents alhora | Que no explotin combinades en subclasses | Bridge |
| Quantes responsabilitats extres porta un objecte | La seva interfície i el seu nucli | Decorator |
| L'estructura interna (fulla o grup) | El tractament uniforme des de fora | Composite |
| Els passos interns d'un procés multiclasse | La crida única del client | Facade |
| L'algorisme amb què es fa una cosa | El context que l'invoca | Strategy |
| Allò permès segons l'etapa de vida | Les operacions que el client invoca | State |
| Qui reacciona a un canvi | L'objecte que canvia | Observer |
| Qui atén una petició | L'emissor de la petició | Chain of Responsibility |
| Les operacions sobre una estructura | Les classes de l'estructura | Visitor |
| Passos concrets d'un flux | L'esquelet del flux | Template Method |
La taula no substitueix les lliçons: és l'índex invers. La teva feina davant d'un problema real és omplir la primera columna amb honestedat — i si no pots ("tot pot canviar" no és una resposta), és que encara no entens el problema prou bé per posar-hi un patró.
Dues preguntes complementàries afinen les forces:
- La variació és de dades o de comportament? Si les variants només difereixen en valors (tarifa 2,99 vs. 4,99), n'hi ha prou amb configuració o un enum; els patrons paguen quan difereix el codi.
- Qui decideix la variant i quan? El programador en compilar (l'herència pot bastar), la configuració en arrencar (fàbriques, injecció), o l'usuari/estat en calent (Strategy, State)?
Preguntes de diagnòstic per família
Abans de baixar a patrons concrets, classifica el problema. Tres preguntes de triatge:
- El dolor apareix en escriure
new? — qui crea, quina variant, amb quants arguments, amb quin cost → família creacional. - El dolor apareix en dibuixar el diagrama de classes? — interfícies que no encaixen, jerarquies que exploten, subsistemes tentaculars, objectes caríssims → família estructural.
- El dolor apareix en seguir el flux en execució? — qui crida qui, qui s'assabenta de què, on viu un algorisme, què es pot desfer → família de comportament.
I dins de cada família, les preguntes que ja coneixes de les comparatives — aquí condensades:
| Família | Pregunta de diagnòstic | Si la resposta és sí... |
|---|---|---|
| Creacional | El client sap què vol però no quina classe concreta? | Factory Method / Abstract Factory |
| Creacional | La construcció té molts opcionals o passos amb ordre? | Builder |
| Creacional | Crear des de zero és car o el punt de partida és "un com aquell"? | Prototype |
| Creacional | De debò només n'ha d'existir un... i no n'hi ha prou amb injectar-lo? | Singleton (amb la crítica de 02-02) |
| Estructural | Existeix codi correcte amb la interfície equivocada? | Adapter |
| Estructural | Hi ha part-tot amb tractament uniforme? | Composite |
| Estructural | Cal sumar responsabilitats sense tocar la classe ni subclassificar? | Decorator / Proxy (segons qui controli: acarament a 03-09) |
| Comportament | Molts s'han d'assabentar que un ha canviat, sense acoblar-s'hi? | Observer |
| Comportament | Allò permès depèn de l'etapa, amb transicions? | State |
| Comportament | Hi ha algorismes alternatius triats des de fora? | Strategy |
| Comportament | Les peticions s'han d'encuar, auditar o desfer? | Command |
L'arbre de decisió global
Les comparatives de cada mòdul (creacionals, estructurals, comportament) contenen els arbres fins per família. Aquest és el nivell superior que et deixa a la porta de l'arbre correcte:
flowchart TD
A[Problema de disseny<br/>anomenat sense citar patrons] --> B{On fa mal?}
B -- "En crear objectes:<br/>qui, quin, com, quants" --> C[Familia CREACIONAL]
B -- "En l'estructura:<br/>interficies, jerarquies,<br/>composicio, cost" --> D[Familia ESTRUCTURAL]
B -- "En la conducta:<br/>flux, avisos, algorismes,<br/>estat, historial" --> E[Familia COMPORTAMENT]
C --> C1{Varia la classe, la<br/>construccio o l'origen?}
C1 -- Classe concreta --> C2[Factory Method /<br/>Abstract Factory]
C1 -- Construccio complexa --> C3[Builder]
C1 -- Copiar un existent --> C4[Prototype]
C1 -- Instancia unica --> C5[Singleton... o injeccio]
C -.-> CREF[Arbre fi: llico 02-07]
D --> D1{Adaptar, compondre,<br/>embolcallar o simplificar?}
D1 -- Interficie incompatible --> D2[Adapter]
D1 -- "Part-tot / 2 dimensions" --> D3[Composite / Bridge]
D1 -- Embolcallar amb alguna cosa mes --> D4[Decorator / Proxy]
D1 -- Subsistema complex --> D5[Facade / Flyweight]
D -.-> DREF[Arbre fi: llico 03-09]
E --> E1{Avisar, encapsular peticio,<br/>variar conducta o operar<br/>sobre estructures?}
E1 -- Avisar / coordinar --> E2[Observer / Mediator]
E1 -- Peticio com a objecte --> E3[Command / Chain / Interpreter]
E1 -- Variar comportament --> E4[Strategy / State /<br/>Template Method]
E1 -- Estructures i estat --> E5[Iterator / Visitor / Memento]
E -.-> EREF[Arbre fi: llico 04-13]
Usa'l com s'usa una brúixola: t'orienta, no et porta fins a la porta. La confirmació final sempre és contra la intenció del patró i el seu acarament amb el veí confusible.
Tres casos de PideYa resolts amb el mètode
Cas creacional: els contractes de restaurant
El tiquet: "En donar d'alta un restaurant cal generar-ne el contracte. Avui n'hi ha dos tipus (comissió estàndard i tarifa plana premium) i legal n'anuncia un tercer (marketplace pur) per al trimestre vinent. L'alta avui fa new ContracteComissio(...) o new ContractePla(...) segons un if sobre un string."
- Problema sense patró: "el procés d'alta ha de generar el contracte correcte sense conèixer les classes concretes de contracte, perquè els tipus creixen".
- Forces: varia la classe concreta instanciada; ha de romandre estable el flux d'alta (validar → crear contracte → signar → activar). La variació és de comportament (cada contracte calcula liquidacions de manera diferent), no només de dades.
- Família: el dolor és al
new→ creacional. - Diagnòstic: el client sap què vol ("un contracte per a aquest restaurant") però no quina classe? Sí. Famílies completes de productes coordinats per mercat? No, és un producte solt. → Factory Method (o la seva variant amb registre de
Suppliers, com elRegistreNotificadorsde 02-03). - Validació: intenció de Factory Method — "definir una interfície per crear un objecte, deixant que les subclasses decideixin quin" — coincideix. Descartat Abstract Factory: no hi ha família de productes que hagin de ser coherents entre si.
- Filtres: eix de canvi real (tercer tipus al roadmap), dolor present (l'
ifja s'ha duplicat en dos llocs). Endavant.
Cas estructural: l'agregador d'opinions
El tiquet: "Integrem les ressenyes d'un agregador extern. El seu SDK retorna ReviewDTO amb getStars() (0-10) i getBody(); el nostre codi de fitxes espera Opinio amb puntuacio() (0-5) i text()."
- Problema sense patró: "codi extern correcte, interfície que no encaixa amb la nostra".
- Forces: varia el proveïdor extern i la seva interfície; ha de romandre estable el nostre domini (
Opinioi tot allò que la consumeix). No volem queReviewDTOes filtri pel codi. - Família: el dolor és d'encaix d'interfícies → estructural.
- Diagnòstic: existeix codi correcte amb la interfície equivocada? Sí, literalment. → Adapter (
AdaptadorOpinionsExternes implements Opinio), el mateix moviment que l'AdaptadorPayPalde 03-02. - Validació: descartats Facade (no simplifiquem un subsistema propi, en traduïm un d'aliè) i Decorator (no afegim responsabilitats, convertim interfície).
- Filtres: el dolor és immediat (sense adapter, la conversió 0-10 → 0-5 es repetiria a cada punt d'ús). Endavant.
Cas de comportament: la propina al repartidor
El tiquet: "Després del lliurament, el client pot deixar propina. Quan la deixa, cal: abonar-la al repartidor, reflectir-la al seu resum setmanal, sumar-la a les mètriques de la zona i — aviat — disparar-li una notificació d'agraïment."
- Problema sense patró: "un fet puntual (propina registrada) interessa un nombre creixent de mòduls que no s'han d'acoblar al que el produeix".
- Forces: varia qui hi reacciona (avui tres, demà quatre); ha de romandre estable el registre de la propina. Ningú no dirigeix cap protocol: cada interessat reacciona a allò seu.
- Família: el dolor és al flux d'avisos → comportament.
- Diagnòstic: molts s'han d'assabentar que un ha canviat? Sí. Hi ha protocol a dirigir entre ells? No. → Observer, reutilitzant la infraestructura d'esdeveniments que ja difon les transicions de la comanda (04-08).
- Validació: descartat Mediator amb la prova del cotó de 04-13 — l'emissor no espera coordinació, només que qui vulgui se n'assabenti.
- Filtres: el quart interessat ja és al roadmap; sense Observer, registrar la propina acumularia dependències cap a comptabilitat, mètriques i notificacions. Endavant.
Fixa't en el ritme comú: en els tres casos, el patró va ser la conclusió de sis passos, no el punt de partida. I en els tres, hi va haver un descart explícit — saber per què no és el veí val tant com saber per què sí que és l'elegit.
"Espera fins que faci mal"
El mètode té una sortida més, i és la més freqüent en codi sa: encara cap.
Triar patró per endavant — "segur que les promocions acabaran necessitant Interpreter, ho deixo muntat" — és apostar a cegues sobre l'eix de variació futur, i l'aposta gairebé sempre falla: el canvi arriba, però per una altra banda, i l'estructura especulativa fa nosa en comptes d'ajudar. La disciplina professional és la contrària:
- Escriu la versió simple (l'
if, la crida directa, l'enum) i mantén-la neta. - Anota la intenció si intueixes l'eix de canvi: un comentari "si apareix un tercer tipus de contracte, extreure Factory" costa zero i guia el següent.
- Vigila els símptomes: la segona duplicació, el tercer cas del
switch, el test que ja no es pot escriure. Aquest és el dolor real. - Quan faci mal, refactoritza cap al patró — que és barat precisament perquè el codi simple és fàcil de moure. Com fer-ho amb xarxa de seguretat és la lliçó 05-04.
La regla de tres és un bon calibrador: la primera vegada escrius directe, la segona dupliques amb càrrec de consciència, la tercera extreus l'abstracció — perquè amb tres casos ja veus l'eix de variació real en comptes d'imaginar-lo. Els patrons es guanyen, no es planten: era la regla d'or de 01-06, i aquest mòdul la converteix en mètode.
Errors Comuns i Consells
- Començar pel patró ("on uso un Observer?"). És la solució a la recerca de problema. Antídot: obligar-te a escriure la frase del problema sense anomenar patrons; si no surt, encara no hi ha problema.
- Triar per semblança estructural, no per intenció. Strategy i State comparteixen diagrama; Chain i Decorator també. El diagrama mai no decideix: decideix la intenció, i els acaraments de les comparatives existeixen per a això.
- Confondre variació de dades amb variació de comportament. Si les variants només canvien valors, un mapa de configuració guanya qualsevol patró.
- Quedar-se amb el primer candidat. Força sempre un descart explícit ("és X i no Y perquè..."). Si no pots articular el descart, no has acabat el diagnòstic.
- Oblidar l'opció "cap". L'arbre global té una branca invisible que surt de l'arrel: "el codi simple encara no fa mal → espera". És la branca correcta més vegades de les que l'entusiasme admet.
- Consell: posa data a les esperes. "Avui no; revisar quan màrqueting llanci el tercer tipus de cupó" converteix la prudència en decisió registrada, no en oblit.
Exercicis
Exercici 1: del tiquet al diagnòstic
Aplica els sis passos del mètode a aquest tiquet de PideYa: "Els restaurants premium volen personalitzar el tiquet que s'imprimeix a cuina: uns hi afegeixen el logo, altres un missatge del xef, altres el desglossament d'al·lèrgens — i qualsevol combinació dels tres. Avui hi ha una subclasse de TicketCuina per combinació i ja en van cinc". Anomena forces, família, candidat, i el patró que has descartat.
Exercici 2: patró o espera?
Per a cada situació, decideix patró concret o espera (amb la versió simple que hi deixaries), justificant-ho amb les forces:
- "El càlcul de la comissió aplica un percentatge diferent per tipus de restaurant; els tipus són tres, estables des de fa dos anys, i només difereixen en el número."
- "En confirmar una comanda cal avisar cuina. Només cuina. No hi ha res més previst."
- "L'estat de la comanda avui és un enum amb
switchen quatre mètodes; suport demana afegir l'estat EN_ESPERA_RESTAURANT amb regles pròpies de cancel·lació, i és el segon estat nou aquest any."
Exercici 3: reconstruir el diagnòstic
Un company proposa: "per als cupons de descompte, muntem un Abstract Factory amb una fàbrica per tipus de cupó". Els cupons són: percentatge sobre el total, quantitat fixa, i enviament gratis — un sol objecte cadascun, sense famílies coordinades. Escriu (a) quina pregunta de diagnòstic va fallar en la seva anàlisi, (b) quin candidat surt del mètode ben aplicat, (c) com li ho explicaries sense desautoritzar-lo.
Solucions
Solució 1: (1) Problema: "afegir extres opcionals i combinables al tiquet sense una subclasse per combinació". (2) Forces: varien els afegits i les seves combinacions; estable el tiquet base i la seva interfície. (3) Família: estructural — el dolor és l'explosió de la jerarquia. (4) Diagnòstic: sumar responsabilitats sense tocar la classe, componibles en calent? → Decorator, el mateix moviment que els extres de plat de 03-05. (5) Descart: Template Method fixaria les variants per herència i reproduiria l'explosió combinatòria; Strategy variaria l'algorisme sencer d'impressió, però aquí les peces s'apilen, no se substitueixen. (6) Filtres: cinc subclasses ja fan mal — endavant.
Solució 2: (1) Espera: la variació és de dades (un percentatge), no de comportament — un Map<TipusRestaurant, BigDecimal> o el mateix enum amb un camp ho resol; Strategy seria un embolcall buit. (2) Espera: un sol receptor sense previsió de més — crida directa amb la dependència injectada (DIP, testable), i nota d'intenció "si apareixen més interessats, Observer". Muntar Observer per a un observador és la catedral de l'email de benvinguda. (3) Patró: State — segon estat nou en un any (eix de canvi real i recurrent), regles per estat, switch repetit en quatre mètodes (dolor present). El diagnòstic i la mecànica són a 04-09; com migrar el switch sense trencar res, a 05-04.
Solució 3: (a) Va fallar "hi ha famílies de productes que hagin de ser coherents entre si?" — Abstract Factory paga quan es creen diversos productes coordinats (la FabricaMercat creava passarel·la + impostos + tiquet); aquí cada cupó és un producte solt. (b) Les forces reals: varia l'algorisme de descompte, estable el checkout que l'aplica → Strategy (ReglaDescompte amb tres implementacions), i com a molt un Factory Method simple si la creació des del codi del cupó ho demana. (c) Reconeixent l'encert de l'instint ("has vist bé que la creació no ha de ser al checkout") i reconduint amb la pregunta, no amb la conclusió: "quina família d'objectes coordinats crea cada fàbrica?" — la pregunta correcta deixa que el mateix company arribi al descart.
Conclusió
Ja tens el mètode: problema anomenat sense patrons, forces sobre la taula (què varia, què queda estable), triatge per família, preguntes de diagnòstic, validació contra la intenció amb descart explícit, i els filtres de la balança com a darrer control — amb la sortida "espera fins que faci mal" com a resultat legítim i freqüent. És el mateix camí en cada família, i els tres casos de PideYa ho demostren pas a pas. Però el mètode s'ha entrenat aquí amb problemes d'una sola resposta; el codi real teixeix diversos patrons en una mateixa funcionalitat, i allà les decisions es condicionen les unes a les altres. Veure el mètode funcionant a escala — el flux complet d'una comanda, i un mòdul nou construït des de zero triant cada peça — és la lliçó següent: Exemples Pràctics d'Ús de Patrons.
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
