Salta el contingut
 

Diagrames de classes UML

Joan Puigcerver Ibáñez

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Aquest material inclou fragments de codi Java.

L'objectiu no és aprendre a desenvolupar codi Java, sinó entendre els conceptes del diagrama de classes i de la programació orientada a objectes.

UML

UML (Unified Modeling Language) és el llenguatge unificat de modelatge. Es tracta d'un conjunt de notacions gràfiques que serveixen per especificar, dissenyar, elaborar i documentar models de sistemes i, en particular, d'aplicacions informàtiques.

A partir d'aquestes notacions gràfiques o diagrames, les persones responsables de l'anàlisi i del disseny poden descriure les característiques que haurà de tindre l'aplicació que l'equip de desenvolupament crearà posteriorment.

En l'actualitat, és el llenguatge de modelatge de sistemes més conegut i utilitzat. Gaudeix d'una acceptació pràcticament universal i, entre altres beneficis, ha impulsat el desenvolupament de ferramentes de modelatge gràfic del programari orientat a objectes.

La notació UML té els avantatges següents:

  • Notació gràfica: es basa en una notació gràfica concreta i fàcil d'interpretar, que es completa amb explicacions escrites.
  • Flexibilitat: permet utilitzar només els diagrames que es consideren oportuns, i amb el grau de detall adequat a les característiques del sistema.
  • Visió global: permet tindre una visió global del sistema que s'ha d'implementar.
  • Reutilització: promou la reutilització.

No obstant això, cal tindre en compte que:

  • UML no és una metodologia, sinó una notació.
  • UML no és un llenguatge de programació.
  • Pot resultar complex conéixer totes les possibilitats del llenguatge.

UML inclou una gran varietat de diagrames, que es classifiquen en estàtics (Figura 1) i dinàmics (Figura 2).

Diagrames estàtics

Institut Obert de Catalunya

Figura 1. Diagrames estàtics.

Diagrames dinàmics

Institut Obert de Catalunya

Figura 2. Diagrames dinàmics.

Aquesta unitat didàctica se centra en un dels diagrames estàtics: el diagrama de classes.

Diagrames de classes

Un diagrama de classes és un diagrama estàtic que representa les classes que s'utilitzaran dins del sistema i les relacions que hi ha entre elles. És un dels diagrames més utilitzats en les fases d'anàlisi i de disseny basades en UML.

En aquestes fases es comença a crear el model conceptual de les dades que utilitzarà el sistema. Per això, s'identifiquen els components (amb els seus atributs i funcionalitats) que prendran part en els processos i es defineixen les relacions que hi haurà entre ells.

Un diagrama de classes inclou alguns conceptes que ajuden a entendre'n la creació i el funcionament (Figura 3):

  • Classe, atribut i mètode (operacions o accions).
  • Visibilitat.
  • Objecte i instanciació.
  • Relacions: associació, herència, composició i agregació.
  • Classe associativa.
  • Interfícies.

Resum dels elements d'un diagrama de classes

Institut Obert de Catalunya

Figura 3. Resum dels elements d'un diagrama de classes.

Classes, atributs i mètodes

Una classe és una representació d'un objecte del món real o abstracte, compost d'atributs, que representen les característiques de l'objecte, i de mètodes, que en representen les accions.

El nom de les classes s'escriu amb la notació UpperCamelCase, és a dir, comença en majúscula i cada paraula comença també en majúscula (CicleFormatiu).

Atributs

Els atributs (també anomenats propietats o característiques) són les dades que contenen els objectes. Els valors dels atributs corresponen a cada objecte que instancia la classe i fan que tots els objectes siguen diferents entre si.

Cada atribut té assignat un tipus i una multiplicitat. El nom dels atributs s'escriu amb la notació lowerCamelCase, és a dir, comença en minúscula i cada paraula següent comença en majúscula (dataNaixement).

El tipus indica la naturalesa de les dades (numèriques, alfanumèriques, booleanes...). Els tipus poden ser:

  • Tipus primitius: tipus de dades bàsiques que proporciona el llenguatge de programació, com int, char, boolean o float.
  • Tipus derivats: tipus de dades que es creen a partir de tipus primitius, com String o Date.

Més informació

La multiplicitat indica quants valors diferents pot tindre un atribut:

Valor Significat
1..1 o 1 Exactament un valor. És el valor per defecte si no s'especifica cap multiplicitat.
0..* Múltiples valors, però és possible que no en tinga cap.
1..* Múltiples valors, però com a mínim un.
m..m o m Exactament m valors. Per exemple, 3..3 són exactament 3 valors.
m..n Interval de m a n: com a mínim m valors i com a màxim n. Per exemple, 1..3.

Mètodes

Els mètodes implementen les accions que es poden dur a terme sobre els atributs. Permeten aplicar canvis sobre els atributs, però també moltes altres accions relacionades amb l'objecte, com obrir-lo, tancar-lo, carregar-lo o fer càlculs.

Cada mètode es defineix amb un nom, els paràmetres que rep i el valor que retorna:

  • Paràmetres: tenen nom, tipus i multiplicitat.
  • Valor de retorn: si n'hi ha, només té tipus i multiplicitat.

A més, els mètodes poden llançar excepcions, que són errors que poden ocórrer durant l'execució del codi. Si un mètode pot llançar alguna excepció concreta, cal indicar-ho.

Representació

Les classes es representen amb un rectangle dividit en tres apartats (Figura 4):

  • Nom: el nom de la classe.
  • Atributs: els atributs de la classe, amb la seua visibilitat i el seu tipus.
  • Mètodes: els mètodes de la classe, amb la seua visibilitat, els paràmetres i el tipus del valor de retorn.
classDiagram
    class Persona{
        -DNI: String
        -nom: String
        -adreça: String
        -telefon [0..*]: String
        -dataNaixement: Date
        +edat() int
        +afegirTelefon(telefon : String) void
    }

Figura 4. Representació de la classe Persona.

L'objectiu d'aquesta unitat és entendre els conceptes de la programació orientada a objectes.

No cal fer la transformació a codi Java. S'inclou en el material per mostrar un exemple concret d'implementació d'aquesta estructura.

Exemple: Transformació a codi Java

La classe Persona es podria traduir amb el codi següent. És important entendre que el diagrama només defineix l'estructura, però no la implementació concreta.

Persona.java
package ud3.examples.persones;

import java.util.List;
import java.util.ArrayList;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.Duration;

public class Persona {
    // Atributs
    private String dni;
    private String nom;
    private String adreça;
    private List<String> telefons;
    private LocalDate dataNaixement;

    // Constructor
    public Persona(String dni, String nom, String adreça, String dataNaixement) {
        this.dni = dni;
        this.nom = nom;
        this.adreça = adreça;
        this.telefons = new ArrayList<>();
        this.dataNaixement = LocalDate.parse(dataNaixement, DateTimeFormatter.ofPattern("dd/MM/yyyy"));
    }

    // Mètodes
    public int edat() {
        LocalDate dataActual = LocalDate.now();
        int days = (int) Duration.between(dataNaixement.atStartOfDay(), dataActual.atStartOfDay()).toDays();
        return days / 365;
    }

    public void afegirTelefon(String telefon) {
        this.telefons.add(telefon);
    }
}

Objectes i instanciació

Un objecte és una instància d'una classe. La instanciació és l'acció de crear una instància d'una classe, i es realitza en temps d'execució mitjançant una crida al mètode constructor de la classe.

És a dir, mentre que una classe defineix el disseny conceptual, un objecte és un element concret d'aquesta classe.

Exemple: Instanciació de la classe Persona

A partir de la classe Persona, es poden crear diferents objectes amb aquesta estructura, amb valors diferents i independents entre ells (Figura 5).

Instància de la classe Persona

Figura 5. Instància de la classe Persona.

En Java, els objectes es creen amb l'operador new:

CrearPersones.java
package ud3.examples.persones;

public class CrearPersones {
    public static void main(String[] args) {
        Persona p1 = new Persona("12345678S", "Joan", "C/Còrsega", "25/07/1988");
        Persona p2 = new Persona("87654321T", "Marta", "Av. Cardenal Benlloch", "01/04/1995");

        p1.afegirTelefon("+34 654876195");

        System.out.printf("Edat de Joan: %d\n", p1.edat());
        System.out.printf("Edat de Marta: %d\n", p2.edat());
    }
}

Visibilitat

La visibilitat d'un atribut o d'un mètode defineix l'àmbit des del qual es pot utilitzar. Aquesta característica està directament relacionada amb l'encapsulació, un concepte de l'orientació a objectes que permet a cada objecte decidir quina part de la seua informació és pública per a la resta.

Les possibilitats per a la visibilitat, tant d'atributs com de mètodes, són:

  • + o public: l'element és accessible des de tots els altres elements del sistema.
  • - o private: l'element només és accessible des dels elements del mateix objecte.
  • # o protected: l'element només és visible per als elements del mateix objecte i per als objectes que en són especialitzacions (herència).
  • ~ o package: l'element només és visible per als elements del mateix paquet.

En Java, es considera una bona pràctica no definir atributs com a public. Si cal accedir a un atribut o modificar-lo des d'una altra classe, es defineixen els mètodes get (getter) i set (setter).

Els mètodes get i set es poden indicar en el diagrama (Figura 6), tot i que aquesta notació no està definida en l'estàndard UML1.

classDiagram
    class Persona{
        -DNI: String
        «get» -nom: String
        «get/set» -adreça: String
        -telefon [0..*]: String
        -dataNaixement: Date
        +edat() int
    }

Figura 6. Representació de la classe Persona amb getters i setters.

Exemple: Getters i setters en Java

La classe anterior es tradueix amb el codi següent:

public class Persona {
    // Atributs
    private String dni;
    private String nom;
    private String adreça;
    private List<String> telefons;
    private LocalDate dataNaixement;

    // Constructor
    public Persona(String dni, String nom, String adreça, List<String> telefons, String dataNaixement) { ... }

    // Mètodes
    public int edat() { ... }

    // Getters i setters
    public String getNom(){
        return this.nom;
    }

    public String getAdreça(){
        return this.adreça;
    }
    public void setAdreça(String adreça){
        this.adreça = adreça;
    }
}

S'observa que l'atribut nom només té getter, mentre que adreça té getter i setter.

Enumeracions

Una enumeració és una classe que representa un tipus de dada que només permet un conjunt definit de valors.

Les enumeracions es representen amb un rectangle amb el nom en UpperCamelCase, i els valors s'escriuen en MAJÚSCULES, ja que es consideren constants.

Exemple: Enumeració DiaSetmana

L'enumeració DiaSetmana només permet els valors DILLUNS, DIMARTS, DIMECRES, DIJOUS, DIVENDRES, DISSABTE i DIUMENGE (Figura 7).

Exemple d'enumeració

Figura 7. Exemple d'enumeració DiaSetmana.

Relacions entre classes

Les relacions d'un diagrama de classes especifiquen quines classes estan relacionades. Per relació s'entén que un objecte interactua d'alguna manera amb un altre objecte.

Si una classe té una altra classe com a atribut, totes dues estan relacionades, i aquest atribut es defineix en l'associació entre elles.

Exemple: Relació entre classes

La classe Habitació està relacionada amb la classe Persona, ja que Habitació conté un objecte Persona com a atribut (Figura 8).

Figura 8. Associació entre les classes Habitació i Persona.

Les relacions també tenen una multiplicitat, que especifica amb quants objectes d'una classe es relaciona cada objecte de l'altra classe. Les multiplicitats s'especifiquen de la mateixa manera que la multiplicitat dels atributs (vegeu Atributs).

Exemple: Relació amb multiplicitat

En l'exemple anterior, s'observa que una Habitació està relacionada amb una Persona amb una multiplicitat 1 a 1..*. És a dir:

  • Una Habitació està relacionada amb una única Persona, que s'emmagatzema en l'atribut client.
  • Una Persona pot estar relacionada amb més d'una Habitació.

Associació

Les relacions entre classes, en general, s'anomenen associacions. Una associació és una relació estructural que defineix les connexions entre dos o més objectes, i es representa amb una línia contínua, sense fletxes ni cap altre símbol en els extrems.

Una associació amb dos extrems és binària, com en el cas d'un client que reserva una habitació d'hotel. Una associació amb tres extrems és ternària (Figura 9).

Exemple d'associació ternària

Institut Obert de Catalunya

Figura 9. Exemple d'associació ternària.

Associació reflexiva

Una associació reflexiva és una associació d'una classe amb ella mateixa. Aquest tipus d'associació és útil per modelar relacions jeràrquiques o recursives.

Exemple: Associació reflexiva

La classe Categoria pot contindre subcategories, que també són de la classe Categoria (Figura 10).

Figura 10. Exemple d'associació reflexiva Categoria.

La navegabilitat especifica si una instància d'una classe pot accedir eficientment als objectes de l'altra classe de la relació. Pot ser de tres tipus:

  • No especificada: no s'indica si es pot navegar d'un objecte a l'altre. És el valor per defecte.
  • Navegable: sí que es pot navegar d'un objecte a l'altre. S'indica amb una fletxa oberta en l'extrem de l'associació.
  • No navegable: no es pot navegar d'un objecte a l'altre. S'indica amb una X en l'extrem de l'associació.

Exemple de navegabilitat en una associació

Institut Obert de Catalunya

Figura 11. Exemple de navegabilitat en una associació.

En la Figura 11, per exemple, s'indica que A4 pot accedir a B4, però que B4 no pot accedir a A4.

Agregació

Una agregació és un cas especial d'associació entre dos o més objectes, del tipus tot-part. Hi intervenen dos tipus d'objectes: l'objecte base i els objectes que hi estan inclosos.

Si l'objecte base desapareix, els objectes inclosos no desapareixen i continuen existint amb les seues funcionalitats pròpies. L'agregació es representa amb una línia contínua que acaba amb un rombe buit en l'extrem de l'objecte base.

Exemple d'agregació

Institut Obert de Catalunya

Figura 12. Exemple d'agregació.

En la Figura 12, l'objecte base és Fruiteria, que inclou els objectes Pomes, Taronges, Peres i Maduixes. Entre aquestes classes hi ha una relació tot-part, on les fruites són part de la fruiteria. No obstant això, si la fruiteria deixa d'existir, les fruites continuen existint.

Composició

Una composició és també una associació del tipus tot-part, molt semblant a l'agregació. La diferència és que hi ha una dependència d'existència entre l'objecte base i els objectes inclosos.

És a dir, si l'objecte base deixa d'existir, els objectes inclosos també deixen d'existir: el temps de vida de l'objecte inclòs depén del temps de vida de l'objecte base. La composició es representa amb una línia contínua que acaba amb un rombe ple.

Exemple de composició

Figura 13. Exemple de composició.

En la Figura 13, l'objecte base Cotxe es compon dels objectes Volant, Roda, Fre i Deposit. Sense l'objecte Cotxe, la resta d'objectes deixen d'existir.

Dependència

Una dependència és una relació semàntica entre dues classes: si hi ha un canvi en l'objecte independent, l'objecte dependent es veu afectat.

Es representa amb una fletxa discontínua entre els dos elements. L'objecte del qual ix la fletxa és el dependent, i l'objecte al qual arriba és l'independent.

Exemple de dependència

Figura 14. Exemple de dependència.

En la Figura 14, l'objecte Grup depén de l'objecte CicleFormatiu. Per exemple, el Grup DAW1 depén del CicleFormatiu DAW: si canvia la denominació o els continguts del cicle DAW, el grup DAW1 es veu afectat.

Herència, especialització o generalització

La generalització és una relació d'herència entre classes. Una de les classes és la classe mare o superclasse, i les altres són les classes filles, subclasses o especialitzacions, que hereten els atributs, els mètodes i el comportament de la classe mare.

Aquesta relació es representa amb una fletxa que ix de la classe filla i acaba en la classe mare.

Exemple de relació de generalització

Figura 15. Exemple de relació de generalització.

En la Figura 15, la classe Animal és la classe mare, i les classes Gos i Gat en són especialitzacions. Les subclasses contenen els atributs i mètodes de la classe Animal, però cadascuna pot implementar mètodes nous o tindre atributs nous.

Classe associativa

Quan una associació té atributs o mètodes propis, es representa com una classe associativa, unida a la línia de l'associació mitjançant una línia discontínua. Tant la línia com el rectangle de la classe representen el mateix element conceptual: l'associació.

Exemple de classe associativa

Institut Obert de Catalunya

Figura 16. Exemple de classe associativa.

En la Figura 16, la classe Estudiant està relacionada amb la classe Assignatura: cada estudiant pot cursar diverses assignatures, i cada assignatura pot tindre molts estudiants. A més, cada estudiant té una nota determinada en cada assignatura. Aquesta situació es pot modelar amb una classe associativa.

Recursos addicionals

Els recursos següents amplien els continguts d'aquests apunts:

Exemples

Aquests diagrames de classes complets permeten vore com s'apliquen els conceptes anteriors:

Bibliografia

Aquest material és una obra derivada del material següent:

Altres referències consultades:

📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.