Introducció al diagrama estàtic UML

A l’hora de resoldre un problema, no sol ser una bona idea començar a anar per feina sense aturar-se un moment a pensar què es vol fer i, en el cas de problemes complexos, cal idear sobre el paper un petit esquema o croquis de què cal fer. Llavors, sobre el paper, es pot reflexionar si la solució sembla tenir sentit i es pot anar refinant, ja sigui un mateix o amb l’ajut d’altres entesos. Fins que no s’arriba a una solució satisfactòria, no es comença la feina. En el cas d’un problema d’una disciplina complexa, evidentment, cal anar una mica més enllà i no n’hi ha prou només amb un croquis ad hoc. Els plànols d’un arquitecte per fer un gratacels no són simples esbossos. Cal un mecanisme formal per descriure el problema i la solució, de manera que tota persona implicada pugui plasmar les seves idees de manera que tothom l’entengui. El desenvolupament d’aplicacions no és una excepció.

Un dels avantatges més importants de la metodologia de l’orientació a objectes, i el principal motiu que l’ha fet rellevant, és que ha permès establir un llenguatge unificat per representar dissenys: el llenguatge UML (unified modelling language). D’aquesta manera, el desenvolupament del programari es pot equiparar a la resta de disciplines tècniques, en les quals és possible generar un esquema d’allò que es vol crear, que pot ser interpretat per qui s’encarregarà de fabricar-ho, sense necessitat que el constructor hagi format part del procés de disseny. A més a més, també és possible que altres experts externs avaluïn l’esquema abans de la fabricació, de manera que es puguin detectar errades abans de consumir cap recurs. Aquesta possibilitat és molt valuosa quan es tracta de crear sistemes complexos.

En el cas concret del desenvolupament del programari, quan parlem de constructor ens referim a un programador.

L’UML és un llenguatge estàndard que permet especificar amb notació gràfica programari orientat a objectes.

Els orígens de l’UML es remunten a l’any 1994, quan Grady Booch i Jim Rumbaugh van començar a unificar diferents tècniques de modelització orientada a objectes, en un intent de trobar una solució satisfactòria als problemes que els dissenyadors tenien a l’hora d’especificar el programari. Al llarg d’aquest procés, s’hi va unir Ivar Jacobson. Cadascú va aportar el propi mètode: el mètode Boosch, OMT (object modelling technique, ‘tècnica de modelització d’objectes’) i OOSE (object oriented software engineering, ‘enginyeria de programari orientada a objectes’).

L’UML no està limitat al programari, sinó que també permet especificar altres sistemes com, per exemple, models de negoci.

Els motius principals que els van dur a unir esforços van ser tres:

  • Evitar que cada mètode evolucionés independentment, cosa que portaria a una situació amb molts mètodes heterogenis que seria perjudicial per als dissenyadors.
  • Establir una notació única que aportés certa estabilitat al camp de l’orientació a objectes. Això era molt important per tal que el diferent programari de suport a la metodologia fos compatible entre si.
  • Trobar millores mitjançant la col·laboració entre ells, partint de l’experiència individual en la creació de cada mètode.

L’OMG és una organització sense ànim de lucre amb l’objectiu d’impulsar les tecnologies basades en l’orientació a objectes.

L’any 1996 van fer la seva proposta d’UML 0.9, subjecta a l’escrutini i els comentaris de la comunitat, la qual es va convertir en objectiu estratègic de diverses organitzacions, com Digital, Hewlett-Packard, Oracle o Microsoft. Els esforços d’aquestes organitzacions van ser canalitzats per l’Object Management Grup (OMG, Grup de Gestió d’Objectes), que va donar lloc a l’UML 1.0. En els anys següents, l’UML ha seguit evolucionant i se n’han fet noves versions, que es continuen utilitzant dins el procés de disseny d’aplicacions.

Esquema general de resolució de problemes mitjançant orientació a objectes

A nivell general, els passos ordenats per resoldre un problema usant orientació a objectes es poden resumir en:

  1. Plantejar l’escenari descriptivament, amb llenguatge humà. Com més detallada sigui la descripció, més fàcil serà la feina.
  2. Localitzar, dins la descripció de l’escenari, els elements que es consideren més importants: els que realment interactuen amb vista a resoldre el problema. Aquests seran els objectes del programa. Normalment, solen ser substantius dins la descripció.
  3. Considerar quins elements són d’una certa complexitat. Redefinir-los com a agrupacions d’objectes més simples. Una bona estratègia és partir del fet que tot l’escenari en si és un objecte complex (igual que una màquina també és un objecte complex) i anar-lo descomponent en parts més petites.
  4. Agrupar els diferents objectes segons el tipus: quins objectes veiem que tenen propietats o comportaments idèntics. Cada tipus d’objecte serà una classe que caldrà especificar.
  5. Identificar i enumerar les característiques dels objectes de cada classe: quines en són les propietats (els atributs) i el comportament (les operacions que ofereixen). N’hi ha prou amb una llista general, escrita en llenguatge humà però suficientment entenedora.
  6. Establir les relacions que hi ha entre els objectes de les diferents classes a partir del paper que interpreten en el problema general. Els objectes no es generen en un buit, sinó que estan relacionats entre si, de la mateixa manera que les peces d’una màquina o els elements d’un edifici no floten en l’aire, sinó que estan connectats per formar un tot. De la mateixa manera, un cop identificats els objectes que conformen el problema a resoldre (el programa que es vol fer, en aquest cas), cal identificar com es relacionen entre ells. Normalment, aquesta mena d’enllaços es pot identificar com “un objecte d’aquest tipus conté objectes d’aquesta altra classe” o “una instància d’aquesta classe gestiona instàncies d’aquesta altra classe”. A mode d’ajut, es pot generar un mapa d’objectes.
  7. Per a cada classe, especificar-ne formalment els atributs i les operacions, extrets a partir de la llista de propietats dels seus objectes dels punts 5 i 6. Normalment, especificar-ne els atributs és un procés més immediat que l’especificació de les operacions.

UML ofereix una notació formal per poder plasmar tots els elements resultants de cadascun dels passos: classes, atributs, mètodes, relacions entre objectes… El resultat final d’aquest procés seguint la notació UML és un esquema anomenat diagrama estàtic UML.

Un diagrama estàtic UML mostra el conjunt de classes i objectes importants que formen part d’un sistema, juntament amb les relacions existents entre aquestes classes i objectes. Mostra d’una manera estàtica l’estructura d’informació del sistema i la visibilitat que té cadascuna de les classes, donada per les seves relacions amb les altres en el model.

Mitjançant UML també és possible definir formalment molts altres aspectes del comportament de l’aplicació (comportament dinàmic, relacions entre crides a mètodes…), però aquí ens centrarem en el diagrama estàtic, que és la base de tot.

Definició de classes mitjançant UML

La peça fonamental d’un diagrama estàtic són les classes, ja que, de fet, el codi d’un programa orientat a objectes es compon de classes, on es defineixen els atributs i els mètodes de què disposaran les seves instàncies (els objectes) quan el programa s’executi. Per tant, abans de poder crear un diagrama complex, el primer pas és identificar-les i saber com representar-les en UML.

En UML, una classe es representa en format complet mitjançant una caixa dividida horitzontalment en tres parts. La part superior compleix exactament la mateixa funció i té el mateix format que en el format simplificat, i és on consta el nom de la classe. En la part del mig es defineixen els atributs que tindran les seves instàncies. Finalment, en la part inferior, es defineixen les operacions que es poden cridar sobre qualsevol de les seves instàncies. L’aspecte és el que es mostra en l’exemple de la figura.

Figura Notació formal d’una classe en UML.

Definició d'atributs

En definir una classe, els atributs s’especifiquen segons la sintaxi següent. El camp de valor inicial es correspon al valor que pren l’atribut en el moment d’instanciar un objecte d’aquesta classe. Concretar-lo en l’especificació dels atributs és opcional. Com veieu, el format és semblant a la declaració d’una variable qualsevol en Java.

  1. visibilitat nomAtribut: tipus [= valor inicial]

Nomenclatura

Per a atributs s’usen paraules concatenades, en què la primera inicial està amb minúscula i la resta amb majúscula. Per exemple: elMeuAtribut.

Els dos aspectes més importants de la definició d’un atribut en representar una classe en UML són la seva visibilitat i el seu tipus de dades.

Pel que fa a la seva visibilitat, aquesta indica si l’atribut és accessible directament des d’altres classes. Hi ha diferents tipus de visibilitat, si bé es destacaran els dos més utilitzats: la visibilitat pública i la privada. Tot i que és possible triar entre diverses, normalment, els atributs es defineixen amb visibilitat privada.

L’UML no indica explícitament quin és el significat real de cada tipus de visibilitat, i deixa aquesta tasca a cada llenguatge de programació. El motiu és que aquest terme es refereix a l’accessibilitat a un objecte en l’àmbit del codi. Tot i així, es descriurà quina sol ser la seva interpretació en la majoria de llenguatges de programació orientats a objectes. Cada tipus de visibilitat s’identifica en la definició de l’atribut amb un símbol especial:

  • Un atribut públic s’identifica amb el símbol ”+”. En aquest cas, si una instància a: està enllaçada amb una instància b:, a: pot accedir lliurement als valors emmagatzemats en els atributs de b:.
  • Un atribut privat s’identifica amb el símbol ”-”. No es pot accedir a aquest atribut des d’altres objectes, independentment del fet que existeixi un enllaç o no. A efectes pràctics, és com si no existís fora de l’especificació de la classe i, en conseqüència, només es pot utilitzar en les operacions dins la mateixa classe en què s’ha definit.

Quant al tipus de dades, donat que UML és un mecanisme de notació genèric, no vinculat a cap llenguatge específic de programació, els tipus de dades que es poden usar no són exactament els mateixos que en Java, si es vol ser estricte. Se sol usar el llenguatge natural, en anglès, per indicar el tipus, enlloc d’una paraula clau concreta depenent del llenguatge. Tot seguit s’enumeren els més típics si es fa en català:

Taula Tipus bàsics dels atributs.
Tipus Significat Exemple
Enter Un nombre sense decimals 1, 56, 128, 15487
Real Un nombre amb decimals 1,34, 3,2415, 267,14, 41,0
Caràcter Una lletra A, a, b, g, -, ?, ç
Booleà Cert/fals Cert, fals
Byte Un byte 0x30, 0xA2, 0xFF
Matriu de… (…[ ] ) Un conjunt d’elements… [1, 2, 3], [a, b, c, f, g], [1,2, 3,0]

En el darrer cas, els tipus múltiples es poden especificar de dues maneres diferents, segons la interpretació que es vol expressar:

  • enter[5] indica que hi ha exactament cinc enters.
  • enter[0..5] indica que hi pot haver entre zero i cinc enters.

De totes maneres, també es pot considerar que ja hi ha predefinits un conjunt de tipus de propòsit general, que pràcticament tots els llenguatges suporten d’una manera o d’una altra:

  • String, per especificar tipus de dades que corresponen a cadenes de caràcters, així s’evita haver d’operar amb caràcters.
  • List<nomTipus>, per especificar seqüències d’elements de tipus “nomTipus”, sense cap fita predeterminada. En el camp “nomTipus” s’indica el tipus d’element que conté la llista, per exemple:List<enter>, List<Cita>, List<String> …

Així, doncs, els atributs d’una classe anomenada TipusProducte es poden definir tal com mostra la figura.

Figura Definició d’atributs de la classe TipusProducte

Els atributs de classe són especialment útils per definir constants.

A part dels atributs que defineixen les propietats de cada instància d’una classe, hi ha un tipus especial d’atributs, anomenats atributs de classe o estàtics. A l’hora de definir-los, es diferencien amb un subratllat i, si són constants, normalment estan escrits amb el nom en majúscules. A part d’això, la sintaxi és idèntica als atributs genèrics.

  1. visibilitat nomAtributClasse: tipus [= valor inicial]

Per exemple:

  1. +PI: real

Definició de mètodes

La convenció de nomenclatura d’una operació és idèntica a la dels atributs.

Dins la definició d’una classe, les operacions disponibles s’especifiquen en UML de la manera següent:

visibilitat nomOperació (llistaParàmetres): tipusRetorn

El camp “llistaParàmetres” té el format següent:

nomParàmetre1: tipus, ... , nomParàmetreN: tipus

Recordeu que el ”+” abans del nom indica que les operacions tenen visibilitat pública.

Totes les explicacions donades per als tipus o la visibilitat en el cas dels atributs també són aplicables a les operacions. En aquest cas, normalment les operacions solen ser públiques, i es deixen com a privades operacions que es consideren auxiliars, o que simplement faciliten la comprensió de les tasques que duran a terme les instàncies de les classes, però que no es poden invocar des de cap altra part del futur codi.

Alguns exemples d’especificacions d’operacions poden ser:

+afegirMèdia (m: Mèdia)
+ajustarVolum (v: enter)
+pausa/reanuda ()
+mèdiaSegüent(): Mèdia

Addicionalment, hi ha un conjunt d’operacions que no sempre cal especificar, ja que se suposen en dissenyar una classe: les operacions accessores. S’acostumen a considerar operacions o mètodes accessors els que donen accés de lectura o d’escriptura als atributs d’una classe. La nomenclatura estàndard per a l’accessor d’escriptura (per modificar el valor de l’atribut) i de lectura (per consultar-lo) és, respectivament:

  • setNomAtribut (valor: tipus).
  • getNomAtribut(): tipus.

Per tant, en l’especificació d’una classe no cal explicitar tots els accessors entre les seves operacions. Per a cada atribut especificat ja es dóna per entès que sempre hi ha les operacions set i get associades, a menys que es digui el contrari.

La figura mostra una representació UML de les operacions d’una classe anomenada Lector.

Figura Especificació d’operacions de la classe Lector.

Relacions entre classes

Un cop identificades les classes dels objectes que componen el problema a resoldre, el pas següent és establir quines relacions hi ha entre elles i representar-les dins el diagrama estàtic UML. De fet, les relacions són el punt especialment rellevant d’un diagrama estàtic UML, ja que, en cas contrari, les classes queden representades en un buit, disperses. Només es disposa d’una llista de classes i prou, sense cap idea de com col·laboren entre elles o quin sentit tenen dins l’aplicació futura. En el diagrama estàtic, cada relació indica que hi ha una connexió entre els objectes d’una classe i els d’una altra. Fent un símil amb una màquina, l’existència d’una relació és equivalent al fet que dues de les seves peces estiguin connectades entre elles.

Associacions

El tipus de relació més freqüent és l’associació.

Es considera que hi ha una associació entre dues classes quan es vol indicar que els objectes d’una classe poden cridar operacions sobre els objectes d’una altra.

Per tant, perquè dos objectes puguin interactuar hi ha d’haver una associació entre les seves classes al diagrama estàtic UML, de manera que es considera que estan enllaçats. En cas contrari, la crida d’operacions no és possible. Quan per mitjà d’un enllaç un objecte objecteA: crida una operació sobre un objecte objecteB:, les transformacions fetes per l’operació únicament afectaran l’objecte objecteB:. No n’afectaran cap de la resta d’instàncies que hi hagi en aquell moment que pertanyin a la mateixa classe que l’objecteB:.

Eines CASE

Normalment, els diagrames estàtics UML es generen mitjançant l’ajut d’eines CASE (computer aided software engineering, ‚enginyeria de programari assistida per ordinador’).

El diagrama estàtic UML estarà format en la seva totalitat per la representació gràfica de totes les classes identificades i les relacions que hi ha entre totes elles. En la figura es representen les relacions amb una línia que uneix les classes implicades.

Figura Associació entre classes.

Tot i que les associacions indiquen que hi ha enllaços entre objectes, es representen gràficament en el diagrama respecte a les seves classes. Quan dues classes es representen relacionades, les seves instàncies poden estar enllaçades en algun moment de l’execució de l’aplicació.

Els enllaços són dinàmics. Poden variar al llarg de l’execució de l’aplicació.

Donada una associació, hi ha un conjunt de descriptors addicionals que es poden especificar:

  • En el centre, entre les dues classes implicades, s’especifica el nom de l’associació. Aquest nom indica què representa l’associació a nivell conceptual.
  • En cada extrem de l’associació s’especifica quines són les funcions de les classes implicades. El nom indica, de manera entenedora, el paper que tenen els objectes de cada classe en la relació.
  • Amb una fletxa se n’especifica la navegabilitat. Partint del nom de l’associació i les funcions de les classes, s’ha de poder establir quina és la classe origen i quina la destinació. A efectes pràctics, la navegabilitat indica el sentit de les interaccions entre objectes: a quina classe pertanyen els objectes que poden cridar operacions i a quina els objectes que reben aquestes crides.
  • Juntament amb la funció, s’especifica la cardinalitat, o multiplicitat, de la relació per a cada extrem. La cardinalitat especifica amb quantes instàncies d’una de les classes pot estar enllaçada una instància de l’altra classe.

Si cal, res no impedeix que una associació sigui navegable en ambdós sentits, tot i que no és el cas més freqüent. En aquest cas, no cal posar cap fletxa.

La cardinalitat defineix quantes instàncies diferents d’una classe ClasseA es poden associar amb una instància de la classe ClasseB en un moment determinat de l’execució del programa.

Les cardinalitats més usades solen ser les 1, 1..* i *.

El nombre d’instàncies per a cada cas s’indica amb una llista de nombres enters, ubicada en l’extrem oposat de l’associació. Per exemple, la cardinalitat que indica quantes instàncies de la ClasseB pot enllaçar una instància de la ClasseA s’ubica en l’extrem de l’associació en què està representada la classe ClasseB. En cas que es vulgui indicar un nombre indeterminat, sense fita superior en el nombre d’enllaços, s’utilitza el símbol *. Per establir rangs de valors possibles, s’usen les fites inferior i superior separades amb tres punts.

Diferents cardinalitats i el seu significat

  • 1: Només un enllaç.
  • 0…1: Cap o un enllaç.
  • 2,4: Dos o quatre enllaços.
  • 1…5: Entre un i cinc enllaços (un, dos, tres, quatre o cinc).
  • 1…*: Entre un i un nombre indeterminat. És a dir, més d’un.
  • *: Un nombre indeterminat. És equivalent a 0…*.

Perquè el programa es consideri correcte a l’hora d’implementar el disseny, s’ha de fer el necessari perquè les condicions que expressen les cardinalitats sempre siguin certes. Si una cardinalitat és, per exemple, 1, això vol dir que tot objecte d’aquesta classe sempre està enllaçat amb un, i només un, objecte de l’altra classe. Mai no hi pot haver dins el programa en execució un cas en què no es compleixi aquesta condició.

De tots aquests descriptors, només la navegabilitat i la cardinalitat són imprescindibles (i de les dues, la cardinalitat és la més important), ja que la decisió que es prengui en aquests aspectes dins l’etapa de disseny tindrà implicacions directes sobre la implementació. Les funcions i el nom són opcionals, si bé molt útils amb vista a la comprensió del diagrama estàtic i com a mètode de reflexió per al dissenyador.

En la figura es mostra una representació completa d’una associació, amb tota la informació que cal especificar.

Figura Representació gràfica d’una associació entre classes.

A partir del que expressa la figura, aquestes són algunes de les conclusions a les quals arribaria un observador aliè al procés de disseny:

  • A partir d’(a). Una instància qualsevol de la classe Pàgina pot enllaçar fins a un nombre indeterminat d’objectes diferents de la classe Cita. Això inclou no tenir-ne cap (una pàgina en blanc). Així, doncs, hi ha pàgines que tenen tres cites, d’altres deu, d’altres cap, etc.
  • A partir d’(a). Recíprocament, donat un objecte qualsevol de la classe Cita, només estarà enllaçat a un únic objecte Pàgina. Per tant, no es pot tenir una mateixa cita en dues pàgines diferents (però sí tenir dues citacions diferents i de contingut idèntic, amb els mateixos valors per als atributs, cadascuna a una pàgina diferent). Tampoc no hi pot haver citacions que, tot i ser en l’aplicació, no estiguin escrites a cap pàgina.
  • A partir de (b). Un objecte de la classe Control sempre té un objecte de la classe Lector enllaçat. Per tant, un tauler de control sempre controla un únic lector de mèdia. No es pot donar el cas que un tauler de control no controli cap lector. La inversa també es certa; tot lector és controlat per algun tauler de control.
  • A partir de (b). Donada la navegabilitat especificada, s’està dient que el tauler de control pot cridar operacions sobre el lector, però no a l’inrevés. Això té sentit, ja que és el tauler de control qui controla el lector.
  • A partir de ©. Donat un client, aquest pot estar enregistrat en més d’una sucursal, però almenys sempre ho estarà en una. Mai no es pot donar el cas d’un client donat d’alta en el sistema però que no estigui enregistrat en cap sucursal.

Cada objecte és únic i té la seva pròpia identitat, independentment dels valors dels seus atributs.

Tot i que no és habitual, res no impedeix que dues classes tinguin més d’una associació entre elles. Normalment, aquest cas s’aplica quan es vol fer una diferenciació explícita de diferents tipus de relació o de funcions entre instàncies de cada classe. En la figura es mostra un exemple en què es pot aplicar aquest principi.

Figura Múltiples associacions entre dues classes.

Atès que un transportista pot adoptar diferents papers en la seva relació amb una sucursal, això es pot representar especificant que hi ha diferents tipus d’associació entre sucursals i transportistes.

Tot i la versatilitat dels diagrames estàtics UML, aquests no sempre són capaços de reflectir totes les restriccions necessàries en els enllaços entre objectes de diferents classes. Les associacions indiquen els possibles enllaços, però no especifiquen condicions concretes per a la seva presència. En aquests casos s’utilitza una restricció textual. Aquesta no és més que una frase addicional al peu del diagrama, escrita en llenguatge humà, en què s’explica breument en què consisteix aquesta restricció.

L’object constraint language és un mecanisme formal per expressar restriccions textuals sense usar el llenguatge humà.

Els transportistes

Amb les associacions representades en la figura és possible expressar que sempre hi ha un únic transportista de reserva i diversos de servei. Malauradament, és impossible indicar que un transportista concret, per exemple el transportista2:, no pot ser alhora de reserva i de servei.

Per resoldre aquest problema cal afegir una restricció textual al peu del diagrama que expliqui la condició en la qual es pot complir l’associació “de reserva”: un transportista de reserva no pot estar de servei i viceversa.

Agregacions

Hi ha un tipus d’associació especial mitjançant la qual el dissenyador vol donar un sentit més específic a l’enllaç, com ara que els objectes de certa classe formen part dels objectes d’una altra. Aquest subtipus d’associació s’anomena agregació.

Una agregació és un tipus d’associació especial que especifica explícitament que hi ha una relació de tot-part entre els objectes de l’agregat (el tot) i el component (la part).

En el diagrama estàtic UML, això es representa gràficament afegint un rombe blanc en l’extrem de l’associació on hi ha la classe que representa el tot. Com que amb aquest símbol ja es diu quina és la relació entre els objectes d’ambdues classes, es poden ometre el nom i la funció en els descriptors de l’associació.

Això es mostra en la figura, en la qual es refina l’associació PàginaCita que s’ha mostrat en els exemples anteriors. Una pàgina conté citacions escrites al seu interior i es pot considerar que el que s’ha escrit en una pàgina és part d’aquesta. Per tant, aquest cas és aplicable.

Figura Agregació Pàgina-Cita

De totes maneres, val la pena esmentar que la definició d’aquest tipus d’associació no és gaire estricta, de manera que en la literatura hi ha diverses interpretacions de què vol dir realment conté o és part de. En darrera instància, és una interpretació personal del dissenyador considerar si un tipus d’objecte és realment part d’un altre.

Composicions

Un altre subtipus d’associació amb una semàntica especial són les anomenades composicions. Amb aquestes associacions també s’expressa el concepte de és part de, però anant més enllà: es considera que la classe composta no té sentit sense els seus components. En contraposició, en una agregació, l’agregat sí que té sentit sense cap dels seus components.

Qualsevol associació en què el dissenyador posaria un verb de l’estil , conté, és part de, etc. és una agregació o una composició.

Una composició és una forma d’agregació que requereix que els objectes components només pertanyin a un únic objecte agregat i que, a més a més, aquest darrer no té sentit que existeixi si no n’existeixen els components.

Cal anar amb compte, ja que de vegades és fàcil confondre agregació i composició.

En l’agregació , segons la mateixa definició, la cardinalitat en la banda de l’agregat sempre ha de ser 1.

Aquest tipus d’associació es representa de manera idèntica a una agregació, només que en aquest cas el rombe és de color negre. La figura en mostra un exemple amb l’associació Agenda-Pàgina.

Figura Agregació Agenda-Pàgina Agenda-Pàgina.

Un altre exemple immediat de composició són les associacions que sortirien de en el reproductor multimèdia.

En aquest cas, en usar una composició per representar aquesta associació, el dissenyador expressa que no té sentit una agenda sense pàgines. De fet, conceptualment, el propi conjunt de pàgines és l’agenda en si. Tampoc no pot ser que una mateixa pàgina (es parla de la mateixa pàgina física, no d’una rèplica) sigui de més d’una agenda alhora. En canvi, sí que té sentit una pàgina en blanc sense cap cita, motiu pel qual el cas Pàgina-Cita és una agregació però no una composició.

Classes associatives

Hi ha circumstàncies que fan que el dissenyador consideri necessari afegir propietats addicionals a una associació, el valor de les quals pot variar segons quines siguin les instàncies enllaçades. En definitiva, el dissenyador vol especificar atributs en una associació. Amb aquesta finalitat s’usen les classes associatives.

Les classes associatives representen associacions que es poden considerar classes.

Una classe associativa es representa amb el mateix format que una classe: és una nova classe que cal especificar dins la descomposició del problema. Com es mostra en la figura, una línia discontinua uneix la nova classe amb l’associació que representa.

Figura Exemple de classe associativa

En la classe associativa Petició hi hauria les propietats vinculades a la petició d’un tipus de producte concret dins un encàrrec (per exemple, el nombre de productes que cal enviar o el seu color). Cap d’aquestes propietats no correspon a l’encàrrec ni al tipus de producte. Tot això es plasmarà en forma d’atributs dins d’aquesta classe.

Totes les classes associatives que apareguin en el diagrama estàtic UML s’hauran d’especificar completament, tant pel que fa als atributs com a les operacions. Tot i representar una associació i no un element identificable dins del problema, a efectes pràctics són una classe més, com qualsevol altra.

Una particularitat de les classes associatives és que es poden representar amb classes i associacions normals. Aquest fet és important, ja que és l’única manera de representar-les en un mapa d’objectes i la majoria de llenguatges de programació no suporten les associacions amb aquest tipus de classes vinculades.

Java no suporta directament classes associatives.

Seguint el sentit de la navegabilitat (classe origen - classe destinació) el desenvolupament és el següent:

  1. Eliminar l’associació original.
  2. Generar una associació de la classe origen a la classe associativa. El tipus de la nova associació i la navegabilitat són idèntics a l’original.
  3. Generar una altra associació de la classe associativa a la destinació. La navegabilitat és de classe associativa a destinació.

Ara la classe associativa ja és una classe normal dins el diagrama estàtic UML, però atès que ara hi ha dues associacions, cal adaptar-hi les cardinalitats:

  • La cardinalitat en els extrems oposats a l’antiga classe associativa sempre és 1.
  • La cardinalitat en l’extrem oposat de la classe origen, en què ara hi ha la classe associativa, és la que hi havia respecte a l’antiga classe destinació.
  • La cardinalitat en l’extrem oposat de la classe destinació, en què ara hi ha la classe associativa, és la que hi havia respecte a l’antiga classe origen.

El resultat d’aplicar aquesta traducció es mostra en la figura.

Figura Traducció de classe associativa.

De fet, depenent de les interpretacions que ha fet el dissenyador respecte a la descripció del problema, es pot arribar a aquest diagrama directament des del pas d’identificació de classes. De totes maneres, en fer un diagrama estàtic UML, és recomanable usar classes associatives sempre que apliqui i només fer la traducció en el moment d’implementar.

Associacions reflexives

Atès que una associació indica enllaços entre instàncies d’una classe, res no impedeix que un objecte estigui enllaçat amb objectes del mateix tipus. Quan això passa, es representa mitjançant una associació reflexiva.

Per la seva definició, no es pot aplicar una associació reflexiva a una composició.

Una associació reflexiva és aquella en què la classe origen i la destinació són la mateixa.

Un exemple d’aquest cas es mostra en la figura, en què els clients de l’aplicació de gestió recomanen altres clients. Es tracta d’una associació reflexiva, ja que tant qui recomana com qui és recomanat, un client, pertanyen a la mateixa classe.

Figura Associació reflexiva

Un dels moments en què el dissenyador ha d’anar amb més compte en aquest tipus d’associacions és quan n’especifica la cardinalitat. La cardinalitat a l’origen de la relació sempre ha de preveure el cas 0. En cas contrari, és impossible generar un mapa d’objectes que la satisfaci, ja que s’hi genera un bucle infinit. Això s’ha de tenir en compte, independentment del fet que, conceptualment, afegir-hi cardinalitat 0 tingui sentit o no.

Exemple de bucle infinit: un arbre genealògic

Un exemple d’aquesta problema és l’ús d’una associació reflexiva entre objectes d’una classe Persona per crear un arbre genealògic. Una persona sempre ha nascut a partir de dos pares (pare i mare), que a la vegada també són persones. Per tant, és lògic, i correcte des del punt de vista conceptual, que la cardinalitat en origen sigui 2, i en destinació, * (una persona pot tenir un nombre indeterminat de fills).

Malauradament, si es fa així, és impossible generar un mapa d’objectes que compleixi aquesta cardinalitat. Per a cada objecte :Persona hi ha d’haver dos enllaços provinents d’altres objectes:Persona, i això és impossible tret que hi hagi cicles (cosa que no pot ser en un arbre genealògic). L’única manera d’evitar-ho és establir que la cardinalitat pot ser 0 o 2.

El cas 0 serà una excepció per als objectes :Persona inicials dins el sistema (per als quals no s’enregistrarà quins van ser els pares).

Herència

Finalment, dins un diagrama estàtic UML també s’estableixen les relacions d’herència entre els objectes de diferents classes. Això permet definir relacions d’especialització/generalització, on la classe a la part superior de la relació representa un concepte més general que el de la part inferior, més específic. Aquest tipus de relació normalment també indica que la classe més específica és idèntica a una altra, excepte en alguns petits aspectes on, o bé és diferent, o bé se suposen propietats addicionals.

Per exemple, diferents tipus de fitxers de mèdia es poden vincular entre si d’acord a una relació d’herència tal com mostra la figura. A la dreta es veu quin concepte es considera més general i quin més específic.

Figura Herència dins un diagrama estàtic UML

Exemples de diagrames estàtics

Una vegada s’ha efectuat el procés de descomposició de programes es pot fer un possible diagrama estàtic UML. En cada cas, el diagrama segueix cadascuna de les composicions proposades del problema. Per fer més entenedora la lectura dels diagrames, només s’inclou el nom de les relacions menys evidents.

Per a cada cas, també es representa un possible mapa d’objectes per a un moment determinat de l’execució de l’aplicació. És interessant veure com cada associació al diagrama estàtic es tradueix en un cert nombre d’enllaços entre objectes, sempre respectant la cardinalitat especificada en l’associació.

Una agenda

El primer exemple és molt senzill, amb molts pocs elements i funcionalitats i amb un paral·lelisme clar amb el món real per facilitar-ne la comprensió. Es vol dissenyar una agenda que permeti consultar les dates d’un calendari per a un any concret i apuntar cites a unes hores concretes. En aquest cas, és possible fer un cert paral·lelisme amb el món real, ja que el concepte d’agenda hi existeix. Es pot pensar en l’agenda com un llibre en què es van passant pàgines endavant o endarrere, cadascuna de les quals correspon a un dia. En cada pàgina es poden escriure cites establertes per a unes hores d’inici i de finalització determinades. Aquesta descripció en llenguatge humà seria la que s’ha descrit en el pas 1 de l’esquema d’aplicació de l’orientació a objectes.

Una bona manera de descompondre un problema en objectes és partir de l’element més general i, a partir d’aquí, anar extraient els elements més senzills. Així, doncs, en aquest cas es pot partir d’un objecte agenda, i deduir els elements que el componen. Una agenda es compon de les pàgines, les quals contenen cites.

Per saber exactament el tipus de relacions entre classes, cal establir la relació de dependència entre elles. Per això, també va bé fer-se una idea de si una situació té sentit o no si estiguéssiu tractant amb un objecte del món real. Així doncs, una agenda està formada per pàgines, i no té sentit una agenda sense pàgines, pel que s’està parlant d’una composició. D’altra banda, cal saber la pàgina oberta en tot moment, per la qual cosa cal una altra relació. Aquesta pot ser una simple associació, ja que no compleix cap de les característiques dels altres tipus de relacions. Finalment, les pàgines contenen cites, però sí que té sentit que una pàgina, en un moment donat, encara no tingui cap cita, per la qual cosa es tracta d’una agregació.

El diagrama estàtic UML de l’agenda es mostra en la figura.

Figura Diagrama estàtic UML de l’agenda.

La instància d’Agenda pot tenir dos tipus de relacions amb les pàgines. D’una banda, la de composició: entre totes les pàgines formen l’agenda. A més a més, una agenda també sap per quina pàgina està oberta, que seria la pàgina que es pot llegir en aquest moment.

Un reproductor multimèdia

En aquest exemple es presenta la descomposició d’un sistema de reproducció multimèdia (música, vídeos…). La motivació pot ser crear una aplicació senzilla per a l’ordinador o generar el sistema de control d’un reproductor portàtil (un dispositiu físic). En aquest cas, es parteix de la identificació de classes següent: Reproductor, Mèdia, Control, Lector, Magatzem i Altaveu.

El diagrama estàtic UML del reproductor es pot veure en la figura. En fer-lo, s’ha decidit que el reproductor té dos altaveus, de manera que es pot controlar el mode mono o estèreo. També cal tenir en compte els punts següents:

  • La cardinalitat de la relació Mèdia-Lector especificada en l’extrem de la classe Mèdia (a l’esquerra) indica que hi pot haver moments en què el lector no reprodueix cap cançó (cas 0 de la cardinalitat: el lector reprodueix 0 cançons).
  • La cardinalitat en l’altre extrem expressa que, per a qualsevol cançó, o bé s’està reproduint en el lector (cas 1) o no (cas 0).
  • El magatzem pot ser buit (cas 0 de la cardinalitat “*” en la relació Magatzem - Mèdia).
  • S’ha decidit que la relació entre Magatzem i Mèdia és una agregació, però també es pot interpretar com una associació normal si no es considera que les dades emmagatzemades, les cançons, són part del magatzem i tenen entitat pròpia.
  • La relació “darrera” entre Magatzem i Mèdia expressa quina és la darrera cançó a què s’ha accedit en el magatzem, per fer-ne accés seqüencial.

Figura Diagrama estàtic UML del reproductor.

Una aplicació de gestió

Suposeu que una empresa vol crear una aplicació que gestioni el transport d’encàrrecs d’una sucursal d’una franquícia. Cada sucursal té un conjunt de transportistes assignats, el nombre dels quals pot variar segons la grandària de la sucursal. Cada dia hi ha un transportista que no treballa, però es considera que està en reserva. Cada un disposa del seu propi vehicle, identificat per un número de llicència. Quan un client vol fer un encàrrec, se n’enregistren les dades personals i especifica les condicions de lliurament: dia i hora, adreça… En l’encàrrec fa constar la llista de productes que vol que li serveixin. Tan bon punt es genera un encàrrec, automàticament, ja s’assigna algun transportista perquè el serveixi. Mai no hi ha encàrrecs sense transportista assignat. Els clients també tenen l’opció de recomanar amics seus perquè s’hi apuntin com a clients. Aquest fet es té en compte de cara a algunes promocions o descomptes especials.

En aquest cas, es partirà de la descomposició en les següents classes: Encàrrec, Sucursal, Transportista, Client, TipusProducte. El diagrama estàtic UML de l’aplicació de gestió és el següent, representat en la figura.

Figura Diagrama estàtic UML de l’aplicació de gestió

Els diagrama estàtic i els mapes d'objectes

Una eina útil per reflexionar sobre si una cardinalitat representa allò que el dissenyador vol és crear mapes d’objectes. Es tracta d’esquemes que representen els diferents estats possibles de l’aplicació.

En un mapa d’objectes es mostren tots els objectes instanciats i els enllaços que hi ha entre ells en un moment determinat de l’execució, l’aplicació d’acord amb el que s’ha representat en el diagrama estàtic UML.

Els mapes d’objectes només són una eina de suport, i no s’utilitzen com a mecanisme formal per representar el disseny. En el diagrama estàtic UML ja hi ha tota la informació necessària.

La figura representa un seguit de mapes d’objectes, un per cada cas, amb diferents objectes enllaçats correctament segons la cardinalitat especificada en l’associació. Els enllaços es representen amb fletxes segons la navegabilitat de les associacions. El cas (a) correspon a l’associació PàginaCita, el cas (b) a la Control-Lector i el © a la Sucursal-Client. Damunt de cada mapa representat hi ha un recordatori de la cardinalitat de l’associació.

Figura Exemple de mapes d’objectes

La figura mostra alguns casos d’estats que es considerarien incorrectes segons les cardinalitats especificades en les associacions:

  • El cas (a) és incorrecte, ja que una cita sempre ha d’estar escrita en alguna pàgina (cardinalitat esquerra = 1), i la instància cita3: no ho compleix, en no estar enllaçada a cap objecte :Pàgina. Només seria correcte si la cardinalitat fos, per exemple, 0..1.
  • El cas (b) és incorrecte, ja que un tauler de control només controla un únic lector enllaçat (cardinalitat dreta = 1), i la instància control1: no ho compleix, en estar enllaçada a dues instàncies, lector1: ilector2:. A més a més, un lector només pot estar enllaçat a un únic tauler de control (cardinalitat esquerra = 1), i la instància lector2: tampoc no ho compleix.
  • El cas © és incorrecte, ja que tot client ha d’estar enregistrat en alguna sucursal, i la instància client2: no està enllaçada amb cap.

Figura Exemples d’enllaços incorrectes

Anar a la pàgina anterior:
Referències
Anar a la pàgina següent:
Activitats