<div class="page"> <div class="cover text-center"> <img class="mx-auto" src=/itb/images/logo_mislata.png alt="logo"> # Diagrames de classes UML <div class="text-end fit-content ms-auto my-3 mt-auto pt-3"> <p><strong>Autor:</strong> Joan Puigcerver Ibáñez</p> <p><strong>Correu electrònic:</strong> j.puigcerveribanez@edu.gva.es</p> <p><strong>Curs:</strong> 2024/2025</p> </div> <div> <p class="fw-bold mb-0">Llicència: BY-NC-SA</p> <p class="d-none d-md-block">(Reconeixement - No Comercial - Compartir Igual)</p> <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ca" target="_blank"> <img class="mx-auto" src="/itb/images/license.png" alt="Licence"/> </a> </div><!--license--> </div><!--cover--> </div><!--page--> {:toc} ##### Observacions En aquest material, s'inclouran fragments de codi Java. L'objectiu d'aquest material NO és apendre a desenvolupar el codi Java, sino entendre els conceptes del diagrama de classes i la programació orientada a objectes. ## UML __UML__ és l’acrònim, en anglès, de _Unified Modeling Language_, és a dir, __Llenguatge unificat de modelització__. UML són 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, l’analista i el dissenyador podran recrear les característiques que caldrà que tingui l’aplicació informàtica que els desenvolupadors hauran de crear posteriorment. En l’actualitat és el llenguatge de modelització de sistemes més conegut i utilitzat. Gaudeix d’una acceptació practicament universal i, entre altres beneficis, ha tingut l’efecte d’impulsar el desenvolupament d’eines de modelització gràfica del programari orientat a l’objectes. Els avantatges de la notació UML són els següents: - Es basa en una notació gràfica concreta i fàcil d’interpretar, sent completada amb explicacions escrites. - A l’analista i/o al dissenyador els permet fer ús dels diagrames que consideren oportuns i amb el grau de detall que consideren, en funció de les característiques del sistema. - Permet tindre una visió global del sistema a implementar. - Promou la reutilització. Cal tindre en compte que: - UML no és una metodologia, és una notació. - UML no és un llenguatge de programació. - Pot resultar complex obtenir un coneixement complet de les possibilitats del llenguatge. UML incorpora una gran varietat de diagràmes: ##### Diagrames estàtics ![](/itb/DAM-ED/UD3/img/uml/diagrames_estatics.png){height=500}{.center} ##### Diagrames dinàmics ![](/itb/DAM-ED/UD3/img/uml/diagrames_dinamics.png){height=600}{.center} En aquesta unitat didàctica ens centrarem en els estàtics __Diagrames de classes__. ## Diagrames de classes Els diagrames de classes són uns diagrames de UML, classificat dins els diagrames de tipus estàtic. És un dels diagrames més utilitzats a les metodologies d’anàlisi i de disseny que es basen en UML. Un __diagrama de classes__ representa les classes que seran utilitzades dins el sistema i les relacions que existeixen entre elles.{.box} Aquest tipus de diagrames són utilitzats durant les fases d’anàlisi i de disseny dels projectes de desenvolupament de programari. És en aquest moment en què es comença a crear el model conceptual de les dades que farà servir 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 porta vinculats alguns conceptes que ajudaran a entendre'n la creació i el funcionament en la seua totalitat. Aquests conceptes són: - Classe, atribut i mètode (operacions o accions). - Visibilitat. - Objecte. Instanciació. - Relacions. Herència, composició i agregació. - Classe associativa. - Interfícies. ![](/itb/DAM-ED/UD3/img/uml/resum_uml.png){.center}{height=600} ### Classes. Atributs i mètodes Una __classe__ és una representació d'un objecte del món real o abstracte, el qual està composat d'__atributs__, que representen característiques de l'objecte, i els __mètodes__, que representen les accions de l'objecte.{.box} Es representen amb la notació __UpperCamelCase__, és a dir, comencen en majúscula i cada paraula comença en majúscula. #### Atributs Els __atributs__ (també anomenats propietats o característiques) són les dades detallades que contenen els objectes. Aquests valors corresponen a l’objecte que instancia la classe i fa que tots els objectes siguen diferents entre si.{.box} Cada atribut té assignat un tipus i una mutiliplicitat. Es representen amb la notació __lowerCamelCase__, és a dir, comencen en minúscula i cada paraula comença en majúscula. El __tipus__ indica la naturalesa de les dades (númeriques, alfanumèriques, booleanes, ...). Els tipus poden ser: - [Tipus primitius](https://www.w3schools.com/java/java_data_types.asp). - `int` - `char` - `boolean` - `float` - ... - [Tipus derivats](https://www.w3schools.com/java/java_data_types_non-prim.asp) (altres classes). - `String` - `Date` - ... La __multiplicitat__ indica quants diferents valors poden haver en un atribut: | Possibles valors | Significat | | :- | :- | | `1..1` o `1` | Exactament un valor. Valor per defecte si no s'especifica cap multiplicitat. | | `0..*` | Multiples valors, on es pot donar el cas que no tinga cap. | | `1..*` | Multiples valors, però com a mínim un valor. | | `m..m` o `m` | Exactament `m` valors. _Exemple_: `3..3` seria exactament 3 valors. | | `m..n` | Interval `m` a `n`. `m` valors com a mínim, però no més de `n`. _Exemple_: `1..3` seria com a mínim 1 i com a màxim 3. | #### Mètodes Els __mètodes__ implementen les accions que es podran dur a terme sobre els atributs. Ofereixen la possibilitat d’aplicar canvis sobre els atributs, però també moltes altres accions relacionades amb l’objecte, com obrir-lo o tancar-lo, carregar-lo, fer càlculs...{.box} Cada mètode es defineix amb un nom i cal especificar els paràmetres que reb i el valor que retorna. - Els paràmetres tenen nom, tipus, multiplicitat. - El valor de retorn, si n’hi ha, només té tipus i multiplicitat. Els mètodes poden llançar __Excepcions__, que són errors que poden ocórrer durant l'execució de codi. Si el mètode pot llançar alguna excepció concreta, cal indicar-ho. #### Representació Les classes és representen amb un rectangle dividit en 3 apartats: - El nom de la classe. - Els atributs de la classe. S'especifica la _visibilitat_ i el tipus. - Els mètodes de la classe. S'especifica la _visibilitat_ els paràmetres i el tipus del valor de retorn. ```mermaid classDiagram class Persona{ -DNI: String -nom: String -adreça: String -telefon [0..*]: String -dataNaixement: Date +edat() int +afegirTelefon(telefon : String) void } ``` ::: warning L'objectiu d'aquesta unitat és entendre els conceptes de la Programació Orientada a Objectes. No heu de realitzar la transformació a codi Java. S'adjunta en el material per veure un exemple concret d'implementació d'aquesta estructura. ::: Aquesta classe es podria traduir amb el següent codi: ```java 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. Instanciació Un objecte és una instanciació d’una classe. El concepte instanciació indica l’acció de crear una instància d’una classe. La creació d’una instància d’una classe es refereix a fer una crida al mètode constructor d’una classe en temps d’execució d’un programari. Mentre que una __classe__ defineix el disseny conceptual, un __objecte__ és la especificació d'un element d'aquesta classe.{.box} _Exemple_: ![](/itb/DAM-ED/UD3/img/uml/instancia.png){.center}{height=200} A partir de la classe `Persona`, puc crear diferents objectes utilitzant aquesta estructura, amb diferents valors i independents entre ells. ```java 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 definirà l’àmbit des del qual podran ser utilitzats aquests elements. Aquesta característica està directament relacionada amb el concepte d’orientació a objectes anomenat _encapsulació_, mitjançant el qual es permet als objectes decidir quina de la seva informació serà més o menys pública per a la resta d’objectes.{.box} Les possibilitats per a la visibilitat, tant d’atributs com de mètodes, són: - `+` o `public`, que vol dir que l’element és accessible per tots els altres elements del sistema. - `-` o `private`, que significa que l’element només és accessible pels elements continguts dins el mateix objecte. - `#` o `protected`, que vol dir que l’element només és visible per als elements del seu mateix objecte i per als elements que pertanyen a objectes que són especialitzacions (_herència_). - `~` o `package`, que vol dir que l’element només és visible per als elements continguts ment dins el paquet que on està l’objecte. En Java es considera una bona pràctica NO definir attributs com a `pubilc`. Si volem que es puga accedir o modificar algun atributs des d'una altra classe, cal definir el mètode `get` (getter) i el mètode `set` (setter). Els mètodes `get` i `set` es poden incloure en el diagrama, però realment no està definit en el model UML. ```mermaid classDiagram class Persona{ -DNI: String «get» -nom: String «get/set» -adreça: String -telefon [0..*]: String -dataNaixement: Date +edat() int } ``` ```java 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; } } ``` ### Enumeracions Les __enumeracions__ son classes representen un tipus de dada que sols permet un conjunt definit de valors.{.box} ![](/itb/DAM-ED/UD3/img/uml/enum.png){.center}{height=250} En l'exemple, tenim l'enumeració `DiaSetmana`, que sols permet els valors: `DILLUNS`, `DIMARTS`, `DIMECRES`, `DIJOUS`, `DIVENDRES`, `DISSABTE` i `DIUMENGE`. També tenim la classe `Event` que té lloc en un dia de la setmana determinat. ### Relacions entre classes Les __relacions__ en un diagrama de classes especifiquen quines classes estan relacionades. Per relació s'enten que un objecte interactúe d'alguna manera amb un altre objecte.{.box} En l'exempe, podem veure la classe `Habitació`, que esta relacionada amb la classe `Persona`, on `Habitació` conté un objecte `Persona` com atribut. ![](/itb/DAM-ED/UD3/img/uml/relacio.png){.center}{height=150} Les relacions també tenen assignada una __multiplicitat__, que especifica amb quants objectes d'una classe es relaciona l'altre objecte de l'altra classe. Les multiplicitats s'especifiquen de la mateixa manera que la multiplicitat dels attributs (consultar [taula](#atributs)). Si una classe té una altra classe com a atribut i estan relacionades, aquest atribut es defineix en la associació. En l'exemple anterior, es pot observar que una `Habitació` està relacionada sols amb una `Persona`, però una `Persona` pot estar relacionada amb més d'una `Habitació`. A més, podem veure que la classe `Habitació` té un atribut anomenat `client` que és un objecte de la classe `Persona`. #### Associació Les relacions entre les diferents classes, generalment, s'anomenen __associacions__. Aquestes relacions es representen mitjançant una línia contínua, sense fletxes ni cap altre símbol als extrems. És un tipus de relació estructural que defineix les connexions entre dos o més objectes. Una associació amb dos extrems es diu que és binària; seria el cas de l’exemple d’un client que reserva una habitació d’hotel. Una associació amb tres extrems es diu que és ternària. ![](/itb/DAM-ED/UD3/img/uml/associacio_ternaria.png){.center}{height=300} #### Navegabilitat La __navegabilitat__ especifica si una instància d'una classe pot accedir eficientment als objectes de l'altra classe de la relació. - __No especificat__: No s'especifica si es pot navegar d'un objecte a l'altre. Per defecte. - __Navegable__: Especifica que __sí__ es pot navegar d'un objecte a l'altre. S'indica amb una fletxa oberta al final de la associació. - __No navegable__: Especifica que __no__ es pot navegar d'un objecte a l'altre. S'indica amb una `X` al final de la associació. ![](/itb/DAM-ED/UD3/img/uml/navigability.png){.center}{height=75} En aquest exemple s'indica que `A4` pot accedir a `B4`, però que `B4` no pot accedir a `A4`. #### Agragació Una __relació d’associació d’agregació__ és un cas especial d’associació entre dos o més objectes. Es tracta d’una relació del tipus tot-part. Aquest tipus de relació implica dos tipus d’objectes, l’objecte anomenat base i l’objecte que estarà inclòs a l’objecte base. Si desapareix l’objecte base, el o els objectes que es troben inclosos en l’objecte base no desapareixeran i podran continuar existint amb les seves funcionalitats pròpies. La relació d’associació d’agregació es representa mitjançant una línia contínua que finalitza en un dels extrems per un rombe buit, sense omplir. El rombe buit s’ubicarà a la part de l’objecte base. ![](/itb/DAM-ED/UD3/img/uml/agregacio.png){.center}{height=300} L’objecte base és l’objecte anomenat `Fruiteria`. Els objectes inclosos a la fruiteria són: `Pomes`, `Taronges`, `Peres` i `Maduixes`. S’estableix una relació entre aquestes classes del tipus tot-part, on les fruites són part de la fruiteria. Això sí, si la fruiteria deixa d’existir, les fruites continuen existint. #### Composició Una __relació de composició__ és un cas especial d’associació entre dos o més objectes. És una relació del tipus tot-part. És una relació molt semblant a la relació d’agregació, amb la diferència que hi ha una dependència d’existència entre l’objecte base i l’objecte (o els objectes) que hi està inclòs. Si deixa d’existir l’objecte base, deixarà d’existir també el o els objectes inclosos. El temps de vida de l’objecte inclòs depèn del temps de vida de l’objecte base. La relació d’associació de composició es representa mitjançant una línia contínua finalitzada en un dels extrems per un rombe pintat. ![](/itb/DAM-ED/UD3/img/uml/composicio.png){.center}{height=300} L’objecte base `Cotxe` es compon dels objectes inclosos `Volant`, `Roda`, `Fre` i `Deposit`. Sense l’objecte `Cotxe` la resta d’objectes deixaran d’existir. #### Dependència Un altre tipus de relació entre classes és la __relació de dependència__. Aquest tipus de relació es representa mitjançant una fletxa discontínua entre dos elements. L’objecte del qual ix la fletxa es considera un objecte dependent. L’objecte al qual arriba la fletxa es considera un objecte independent. Es tracta d’una relació semàntica. Si hi ha un canvi en l’objecte independent, l’objecte dependent es veurà afectat. ![](/itb/DAM-ED/UD3/img/uml/dependencia.png){.center}{height=100} L’objecte `Grup` es depenent respecte de l'objecte `CicleFormatiu`. Per exemple, el `Grup` __DAW1__ depén del `CicleFormatiu` __DAW__. Si hi ha canvis en la denominació o els continguts del `CicleFormatiu` __DAW__, el `Grup` es veurà afectat. #### Herència, especializació o generalització La __relació de generalització__ es dóna entre dues classes on hi ha un vincle que es pot considerar d’herència. Una classe és anomenada classe _mare_ o _superclasse_. L’altra (o les altres) són les anomenades classes _filles_, _subclasses_ o _especialitzacions_, que hereten els atributs, els mètodes i el comportament de la classe _mare_. Aquest tipus de relació queda especificat mitjançant una fletxa que ix de la classe filla i que acaba a la classe mare. ![](/itb/DAM-ED/UD3/img/uml/herencia.png){.center}{height=300} La classe `Animal` és la classe mare, i les classes `Gos` i `Gat` son especialitzacions. Les subclasses contenen els mètodes i atributs de la classe `Animal`, però cadascuna d'elles poden implementar nous mètodes o tindre nous atributs. #### Classe associativa Quan una associació té propietats o mètodes propis es representa com una classe unida a la línia de l’associació per mitjà d’una línia discontínua. Tant la línia com el rectangle de classe representen el mateix element conceptual: l’associació. ![](/itb/DAM-ED/UD3/img/uml/classe_associativa.png){.center}{height=300} La classe `Estudiant` està relacionada amb la classe `Assigunatura`. Un estudiant pot cursar diverses assignatures, i una assignatura pot ser cursada per molts estudiants. En aquesta associació, cada un dels alumnes té una determinada nota per cada assignatura. Podem modelitzar aquesta situació utilitzant una __classe associada__. ## Bibliografia i recursos Aquest material és una obra derivada dels materials: - Diagrames estàtics. Institut Obert de Catalunya. https://ioc.xtec.cat/materials/FP/Recursos/fp_dam_m05_/web/fp_dam_m05_htmlindex/WebContent/u3/a1/continguts.html - https://stackoverflow.com/questions/28139621/shortcut-for-denoting-or-implying-getters-and-setters-in-uml-class-diagrams - https://support.bizzdesign.com/display/knowledge/Setting+the+multiplicity+for+a+UML+attribute%2C+operation+or+association - https://www.uml-diagrams.org/association.html ##### Recursos - https://www.youtube.com/watch?v=UI6lqHOVHic