Els patrons de disseny es comuniquen amb diagrames: la secció "Estructura" de qualsevol catàleg és un diagrama de classes, i les col·laboracions entre objectes es mostren amb diagrames de seqüència. Si no llegeixes aquests diagrames amb fluïdesa, cada patró et costarà el doble. La bona notícia: no necessites dominar UML sencer (que té 14 tipus de diagrames); per a aquest curs en tenim prou amb dos —classes i seqüència— i un grapat de relacions. En aquesta lliçó aprendràs exactament aquest subconjunt, veuràs com el dibuixarem amb mermaid a la resta del curs, i practicaràs amb les classes de PideYa que ja coneixes. No és un curs d'UML: és el teu kit de supervivència per llegir patrons.

Contingut

  1. Què és UML i quina part necessitem
  2. El diagrama de classes: classes, atributs i mètodes
  3. Interfícies i classes abstractes
  4. Les sis relacions que has de reconèixer
  5. El diagrama de seqüència bàsic
  6. Com dibuixarem tot això al curs: mermaid

Què és UML i quina part necessitem

UML (Unified Modeling Language) és la notació estàndard (des de 1997) per dibuixar sistemes orientats a objectes. És enorme, però els catàlegs de patrons en fan servir una fracció mínima:

Diagrama Què mostra Per a què el fan servir els patrons
De classes Estructura estàtica: classes, interfícies i les seves relacions La secció "Estructura" de cada patró
De seqüència Interacció dinàmica: quins missatges s'envien els objectes i en quin ordre La secció "Col·laboracions"

Tota la resta (casos d'ús, activitats, estats, desplegament...) queda fora d'aquest curs. Regla d'or en llegir diagrames de patrons: són esquemàtics, no plànols de construcció. Mostren els participants i relacions essencials, ometent getters, constructors i detalls accessoris.

El diagrama de classes: classes, atributs i mètodes

Una classe es dibuixa com una caixa amb tres compartiments: nom, atributs i mètodes.

classDiagram
    class Comanda {
        -Long id
        -List~LiniaComanda~ linies
        -EstatComanda estat
        +calcularTotal() double
        +afegirLinia(LiniaComanda linia) void
        +canviarEstat(EstatComanda nou) void
    }

Com es llegeix cada línia:

  • Visibilitat (el símbol inicial): + públic, - privat, # protegit, ~ de paquet. Als diagrames de patrons gairebé sempre veuràs + en mètodes i - en atributs: l'encapsulació estàndard.
  • Atributs: -Long id significa "atribut privat id de tipus Long". En mermaid els genèrics s'escriuen amb ~: List~LiniaComanda~ és List<LiniaComanda>.
  • Mètodes: +calcularTotal() double és un mètode públic sense paràmetres que retorna double. El tipus de retorn va al final (en UML clàssic s'escriu : double; mermaid ho admet sense els dos punts).
  • Un membre subratllat és estàtic; en mermaid es marca amb $ al final: +getInstancia()$ Comanda. Un en cursiva és abstracte; en mermaid, amb *: +cuinar()*.

En Java, aquesta caixa correspon a:

public class Comanda {
    private Long id;
    private List<LiniaComanda> linies;
    private EstatComanda estat;

    public double calcularTotal() { /* ... */ return 0; }
    public void afegirLinia(LiniaComanda linia) { /* ... */ }
    public void canviarEstat(EstatComanda nou) { /* ... */ }
}

Interfícies i classes abstractes

Els patrons viuen de les abstraccions ("programa contra una interfície", com vam veure a la lliçó anterior), així que distingir-les en un diagrama és vital:

  • Una interfície es marca amb l'estereotip <<interface>> sobre el nom.
  • Una classe abstracta es marca amb <<abstract>> (o el nom en cursiva, en UML clàssic).
classDiagram
    class Notificador {
        <<interface>>
        +notificar(Client client, String missatge) void
    }
    class MetodePagamentBase {
        <<abstract>>
        -String comerciId
        +processar(double quantia)* ResultatPagament
        +registrarIntent() void
    }

Diferència pràctica en llegir un patró: una interfície només declara contracte; una classe abstracta pot a més aportar codi comú a les seves filles (com registrarIntent() a dalt) deixant abstracte el que varia (processar, marcat amb *). Molts patrons es recolzen just en aquesta combinació.

Les sis relacions que has de reconèixer

Aquí hi ha el 80% del valor d'aquesta lliçó. Tota la "gramàtica" dels diagrames de patrons són aquestes sis fletxes:

Relació Significat Notació UML En mermaid Exemple PideYa
Herència "és un" (estén una classe) Fletxa amb triangle buit cap al pare `< --`
Implementació "compleix el contracte de" una interfície Triangle buit amb línia discontínua `< ..`
Associació "coneix" (referència duradora) Línia contínua (opcionalment amb fletxa) --> Comanda coneix Client
Agregació "té un" (tot-part feble: les parts sobreviuen al tot) Rombe buit al costat del tot o-- Repartidor agrupa Vehicle (el vehicle existeix sense ell)
Composició "està compost de" (tot-part fort: les parts moren amb el tot) Rombe ple al costat del tot *-- Comanda es compon de LiniaComanda
Dependència "usa temporalment" (paràmetre, variable local, creació) Fletxa discontínua ..> GeneradorFactures usa Comanda com a paràmetre

I així es veuen totes juntes sobre classes de PideYa:

classDiagram
    class Notificador {
        <<interface>>
        +notificar(Client c, String msg) void
    }
    class MetodePagamentBase {
        <<abstract>>
        +processar(double quantia)* ResultatPagament
    }

    MetodePagamentBase <|-- PagamentTargeta : herència
    Notificador <|.. NotificadorSms : implementació
    Comanda --> Client : associació
    Repartidor o-- Vehicle : agregació
    Comanda *-- LiniaComanda : composició
    GeneradorFactures ..> Comanda : dependència

Claus per no confondre-les:

  • El triangle sempre apunta a l'abstracció (pare o interfície). Línia contínua = herència de classe; discontínua = implementació d'interfície.
  • El rombe va al costat del "tot", no de la part. Per distingir agregació de composició pregunta't: si esborro el tot, té sentit que la part continuï existint? Si la comanda es cancel·la i s'esborra, les seves línies no signifiquen res soltes → composició (rombe ple). Si el repartidor es dona de baixa, la moto continua existint a la flota → agregació (rombe buit).
  • Associació davant de dependència: associació és un atribut (referència que es conserva); dependència és un ús puntual (paràmetre o variable local). En Java: private Client client; és associació; generarPdf(Comanda c) és dependència.
  • Les associacions poden portar multiplicitat: "1" --> "0..*" es llegeix "una comanda té de zero a moltes línies". En mermaid: Comanda "1" *-- "1..*" LiniaComanda.

La correspondència en Java de les tres relacions "de tenir":

public class Comanda {
    private Client client;                                  // Associacio
    private final List<LiniaComanda> linies = new ArrayList<>(); // Composicio:
    // les linies es creen dins de la comanda i ningu mes no les referencia

    public void afegirLinia(Plat plat, int quantitat) {
        linies.add(new LiniaComanda(plat, quantitat));      // neixen i moren amb ella
    }
}

public class Repartidor {
    private Vehicle vehicle;                                // Agregacio:
    public void assignarVehicle(Vehicle v) { this.vehicle = v; } // ve de fora
}

Matís honest: en Java la diferència agregació/composició no la imposa el llenguatge (totes dues són referències); és una intenció de disseny sobre cicle de vida i propietat. Als diagrames de patrons no sol ser crítica: si dubtes, llegeix-la com a "té un".

El diagrama de seqüència bàsic

El diagrama de classes diu qui és qui; el de seqüència diu què passa quan el sistema s'executa: quins objectes hi participen, quins missatges (crides a mètodes) s'envien i en quin ordre temporal (el temps flueix cap avall).

Escenari PideYa: un client confirma la seva cistella i el sistema cobra i notifica.

sequenceDiagram
    participant C as Client
    participant SC as ServeiComandes
    participant MP as MetodePagament
    participant N as Notificador

    C->>SC: confirmar(cistella)
    activate SC
    SC->>SC: crearComanda(cistella)
    SC->>MP: processar(quantia)
    activate MP
    MP-->>SC: ResultatPagament
    deactivate MP
    SC->>N: notificar(client, "Comanda confirmada")
    SC-->>C: comandaConfirmada
    deactivate SC

Elements que has de reconèixer:

  • Participants (a dalt): els objectes involucrats. De cadascun en penja la seva línia de vida vertical.
  • Missatge síncron (->>, fletxa contínua): una crida a mètode; l'emissor espera la resposta.
  • Resposta (-->>, fletxa discontínua): el valor retornat.
  • Barra d'activació (el rectangle sobre la línia de vida, activate/deactivate): l'interval en què aquell objecte està executant alguna cosa.
  • Automissatge (SC->>SC): l'objecte crida un mètode propi.

Als patrons, el diagrama de seqüència respon la pregunta que el de classes no pot respondre: "d'acord, aquestes són les classes... però qui crida qui i quan?". Veuràs que en diversos patrons l'estructura de classes és gairebé idèntica i el que els distingeix és la seqüència; per això convé llegir sempre tots dos.

Com dibuixarem tot això al curs: mermaid

En aquest curs tots els diagrames estan escrits en mermaid, una notació de text que es renderitza com a diagrama. Avantatge per a tu: pots copiar qualsevol diagrama del curs, enganxar-lo a mermaid.live i modificar-lo per experimentar. La xuleta completa del que farem servir:

classDiagram                          %% inicia un diagrama de classes
    class LaMevaClasse {
        <<interface>>                 %% o <<abstract>>
        -tipus atributPrivat
        +metode(Tipus param) TipusRetorn
        +metodeAbstracte()* Tipus     %% * = abstracte
        +metodeEstatic()$ Tipus       %% $ = estatic
    }
    Pare <|-- Filla                   %% herencia
    Interficie <|.. Implementacio     %% implementacio
    A --> B : coneix                  %% associacio (amb etiqueta opcional)
    Tot o-- Part                      %% agregacio
    Tot *-- Part                      %% composicio
    Usuari ..> Usat                   %% dependencia
    A "1" --> "0..*" B                %% multiplicitat

sequenceDiagram                       %% inicia un diagrama de sequencia
    participant A as NomLlegible
    A->>B: crida(args)                %% missatge sincron
    B-->>A: resposta                  %% retorn
    activate B                        %% comenca activacio
    deactivate B                      %% acaba activacio

Amb aquesta xuleta pots llegir el 100% dels diagrames dels mòduls 2 a 6. Quan al mòdul 2 vegis l'estructura d'un patró, ja no estaràs desxifrant fletxes: estaràs llegint disseny.

Errors Comuns i Consells

  • Confondre el sentit del triangle d'herència. El triangle toca l'abstracció (pare/interfície). En mermaid, MetodePagamentBase <|-- PagamentTargeta es llegeix "PagamentTargeta hereta de MetodePagamentBase". Si ho llegeixes al revés, entendràs tots els patrons del revés.
  • Confondre el costat del rombe. El rombe va enganxat al tot (el contenidor), no a la part. Comanda *-- LiniaComanda: el rombe és a Comanda.
  • Intentar que el diagrama ho digui tot. Un diagrama de patró és un esquema: si no hi apareixen els getters o el constructor, no és que no existeixin; és que no importen per entendre el patró. No els afegeixis en dibuixar els teus.
  • Ignorar la diferència entre línia contínua i discontínua. Contínua = relació forta i estructural (herència, associació); discontínua = relació més feble o de contracte (implementació, dependència). Aquest matís canvia el significat del diagrama.
  • Llegir només el diagrama de classes i saltar-se el de seqüència. Diversos patrons comparteixen una estructura estàtica gairebé idèntica; la diferència és a la dinàmica. Acostuma't des d'ara a llegir tots dos.
  • Consell: practica el camí invers. Pren una classe petita d'un projecte teu i dibuixa-la en mermaid amb les seves relacions reals. Dibuixar és el que fixa la notació; només llegir, no.

Exercicis

Exercici 1: de diagrama a Java

Tradueix aquest diagrama a esquelets de classes Java (sense implementar els cossos):

classDiagram
    class Promocio {
        <<interface>>
        +calcularDescompte(Comanda comanda) double
    }
    Promocio <|.. PromocioPrimeraCompra
    CalculadoraDescomptes ..> Promocio
    CalculadoraDescomptes ..> Comanda
    Comanda "1" *-- "1..*" LiniaComanda

Exercici 2: de Java a diagrama

Dibuixa en mermaid (classDiagram) les classes i relacions d'aquest codi, triant bé entre associació, agregació, composició i dependència:

public class Restaurant {
    private final Carta carta = new Carta();        // creada i posseida pel restaurant
    private List<Repartidor> repartidorsFavorits;   // s'assignen des de la flota comuna

    public Factura facturarMes(GeneradorFactures generador) {
        return generador.generarMensual(this);
    }
}

Exercici 3: llegir una seqüència

Observa el diagrama de seqüència de la secció 5 i respon: (a) quin objecte orquestra el procés?, (b) en quin moment està actiu MetodePagament i què retorna?, (c) el missatge a Notificador espera resposta segons el diagrama? Quin missatge és un automissatge?

Solucions

Solució 1:

public interface Promocio {
    double calcularDescompte(Comanda comanda);
}

public class PromocioPrimeraCompra implements Promocio {   // <|.. implementacio
    public double calcularDescompte(Comanda comanda) { return 0; }
}

public class CalculadoraDescomptes {
    // ..> dependencia: usa Promocio i Comanda com a parametres, no com a atributs
    public double calcular(Comanda comanda, Promocio promocio) { return 0; }
}

public class Comanda {
    // *-- composicio 1 a 1..*: la comanda posseeix les seves linies (almenys una)
    private final List<LiniaComanda> linies = new ArrayList<>();
}

public class LiniaComanda { }

Solució 2:

classDiagram
    Restaurant "1" *-- "1" Carta : composició
    Restaurant o-- Repartidor : agregació
    Restaurant ..> GeneradorFactures : dependència
    Restaurant ..> Factura : dependència

Raonament: la Carta la crea i posseeix el restaurant (mor amb ell) → composició. Els repartidors existeixen fora del restaurant i només s'hi associen com a favorits → agregació (una associació simple --> també seria defensable; l'important és descartar la composició). GeneradorFactures i Factura només apareixen com a paràmetre i valor de retorn d'un mètode → dependències.

Solució 3: (a) ServeiComandes: rep la petició del client i crida tots els altres. (b) MetodePagament està actiu només entre la crida processar(quantia) i la seva resposta; retorna un ResultatPagament. (c) Tal com està dibuixat, a notificar(...) no se li dibuixa fletxa de retorn: el diagrama no mostra resposta (es llegeix com una crida el resultat de la qual no interessa en aquest escenari). L'automissatge és SC->>SC: crearComanda(cistella): ServeiComandes invocant un mètode propi.

Conclusió

Ja tens el kit de lectura de diagrames que faràs servir en tot el curs: la caixa de classe amb visibilitats, els estereotips <<interface>> i <<abstract>>, les sis relacions (herència, implementació, associació, agregació, composició i dependència, amb les seves fletxes i rombes ben orientats) i el diagrama de seqüència per a la dinàmica. A més coneixes la sintaxi mermaid exacta amb què estan escrits tots els diagrames del curs, llesta per copiar i experimentar.

Amb les eines de lectura a la mà, toca desplegar el mapa: quants patrons hi ha, com s'organitzen i què fa cada família? Aquest mapa —que és també l'itinerari dels mòduls 2, 3 i 4— és la propera lliçó: Classificació dels Patrons de Disseny.

Curs de Patrons de Disseny de Programari

Mòdul 1: Introducció als Patrons de Disseny

Mòdul 2: Patrons Creacionals

Mòdul 3: Patrons Estructurals

Mòdul 4: Patrons de Comportament

Mòdul 5: Aplicació de Patrons de Disseny

Mòdul 6: Patrons de Disseny Avançats

Mòdul 7: Recursos Addicionals i Conclusió

© Copyright 2026. Tots els drets reservats