Sunteți pe pagina 1din 47

DIAGRAME UML APLICATE

Analiza si design orientate pe obiecte folosind


UML

Student: _________
Calculatoare , anul 4
Grupa: __________
Introducere in UML
UML este un limbaj vizual de modelare destinat vizualizării, specificării, construirii şi
documentării sistemelor de aplicaţii. UML reuneşte cele mai bune tehnici şi practici din
domeniul ingineriei programării, care şi-au dovedit eficienţa în construirea sistemelor complexe.
UML este succesorul propriu-zis al celor mai bune trei limbaje de modelare anterioare orientate
pe obiecte (Booch, OMT, and OOSE).
UML este un limbaj de modelare bazat pe notaţii grafice folosit pentru a specifica,
vizualiza,construi şi documenta componentele unui program. Modelarea vizuala este foarte
benefica in comunicarea dintre dezvoltatorii proiectului si utilizatori.
UML a fost adoptat în cadrul OMG în 1997.

UML in cadrul procesului de dezvoltare


Dezvoltarea de software poate fi facuta prin multe modalitati. Exista cateva tipuri diferite
de procese de dezvoltare pe care le urmeaza proiectele, incluzand totul de la modelul cascada la
procese OOP. Fiecare prezinta avantaje si dezavantaje.
Modelul cascadă defineşte următorii paşi în dezvoltarea unui program:
• Analiza
• Design-ul
• Implementarea
• Testarea
• Acceptarea proiectului
Nu se stipulează cum se fac aceşti paşi (metodologie, notaţii), ci doar ordinea efectuării lor.
Avantajul metodei de dezvoltare în cascadă este acela că o sarcină complexă este împărţită în
mai mulţi paşi mici, ce sunt mai uşor de administrat. Fiecare pas are ca rezultat un produs bine
definit (documente de specificaţie, model, etc.)
Modelul cascada pentru dezvoltare software prezinta dezavantaje pentru ca trebuie facut
backtracking prin pasii modelului iar la inceput trebuie determinate toate cerintele.
Modelul cascada.

Modelul în spirală încearcă să rezolve problemele modelului în cascadă, păstrând


avantajele acestuia: planificare, faze bine definite, produse intermediare.
Modelul în spirală defineşte următorii paşi în dezvoltarea unui produs:
• studiul de fezabilitate
• analiza cerinţelor
• proiectarea arhitecturii software
• implementarea
Modelul în spirală recunoaşte că problema principală a dezvoltării programelor este riscul.
Riscul nu mai este eliminat prin aserţiuni de genul: “în urma proiectării am obţinut un model
correct al sistemului”, ca şi în modelul cascadă. Aici riscul este acceptat, evaluat şi se iau măsuri
pentru contracararea efectelor sale negative.
Exemple de riscuri:
• în timpul unui proces îndelungat de dezvoltare, cerinţele (noi) ale clientului sunt ignorate;
• firma concurentă lansează un program rival pe piaţă;
• un dezvoltator / arhitect părăseşte echipa de dezvoltare;
• echipa nu respectă un termen de livrare pentru o anumită componentă
• clientul schimbă cerinţele.
În modelul spirală se consideră că fiecare pas din dezvoltare conţine o serie de activităţi comune:
• pregătirea: se identifică obiectivele, alternativele, constrângerile;
• gestionarea riscului: analiza şi rezolvarea situaţiilor de risc;
• activităţi de dezvoltare specifice pasului curent (de ex. analiza specificaţiilor sau scrierea de
cod)
• planificarea următorului stadiu: termenele limita, resurse umane, revizuirea stării proiectului.

Modelul de dezvoltare în spirala

O alta metoda este cea interativa unde trecem de mai multe ori peste pasii ce ii avem de
urmat: analiza, design, dezvoltare, testare si lansare.
Intr-un proiect vom trece prin patru faze: inceptie, elaborare, constructie si tranzitie.

• Inceptia este inceputul unui proiect. Adunam informatii si facem verificari de


concept. La sfarsitul inceptiei avem de luat o decizie de a merge mai departe sau nu
pentru proiect.
• In elaborare, use case-urile sunt detaliate si sunt luate decizii arhitecturale.
Elaborarea include analiza, design, codificare si planificare de teste.
• In faza de constructie va fi scris majoritatea codului.
• Tranzitia este pregatirea finala si lansarea sistemului catre utilizator

Orientarea pe obiecte
Un obiect este o entitate care are identitate, stare si comportament. O clasa este o
descriere a unei multimi de obiecte care au aceleasi caracteristici structurale si comportamentale.
Exista anumite principii, asupra carora in general se convine, referitoare la ce inseamna
“orientat obiect”.
Se considera ca dezvoltarea unui program este orientata obiect daca apar urmatoarele
caracteristici:
• incapsularea
• mostenirea
• polimorfismul
In principiu, orice limbaj de programare orientat obiect ar trebui sa ofere suport pentru
constructiile de mai sus. Astfel, ar fi posibil sa transpunem o arhitectura orientata obiect ın orice
limbaj orientat obiect disponibil.
Toate aceste trei caracteristici promoveaza reutilizarea codului. Incapsularea permite ca o
clasa sa fie folosita fara a sti cum functioneaza (modularitate, abstractizare).
Mostenirea permite reutilizarea codului prin folosirea de caracteristici deja existente si adaugarea
de altele noi. Polimorfismul permite scrierea unei clase generale care specifica o interfata a carei
implementare va fi specificata si apelata ıntr-un mod transparent pentru clasele care o mostenesc.
Incapsulare ınseamna punerea ımpreuna a partilor puternic corelate ale unui program ın scopul
crearii de unitati ce pot fi proiectate, implementate, depanate, testate si mentinute una cate una.
Limbajele orientate obiect considera codul si datele ca parte a unei entitati indivizibile numite
obiect. Datele continute ıntr-un obiect sunt de regula modificate doar prin intermediul codului
(metodelor) obiectului respectiv. Fiecare obiect poate fi privit ca un mic procesor a carui
comportare este definita de modul cum raspunde la un apel de metoda.
Intr-un sistem orientat obiect se lucreaza ın mod uzual cu o colectie de obiecte ce coopereaza
pentru a obtine un anumit rezultat.
Ascunderea informatiei: utilizatorii unui obiect nu au nevoie sa stie (nu-i intereseaza, nu trebuie
sa stie) implementarea metodelor. Un utilizator poate modifica starea obiectului doar ın mod
indirect, prin apelul de metode. El nu trebuie sa stie modalitatea ın care modifica metoda starea
obiectului ci doar efectul acestei modificari. Un avantaj al acestei abordari este ca imbunatatiri
ale codului pot apare fara a schimba interfata. Aceasta separare este esentiala pentru producerea
de cod refolosibil si usor de intretinut.

Prezentare generala a diagramelor UML


Diagramele sunt grafuri care prezintă simboluri ale elementelor de modelare (model
element) aranjate astfel încât să ilustreze o anumită parte sau un anumit aspect al sistemului. Un
model are de obicei mai multe diagrame de acelaşi tip.

Diagrama cazurilor de utilizare (Use Case Diagram)

Un caz de utilizare este o descriere a unei funcţionalităţi (o utilizare specifică a sistemului) pe


care o oferă sistemul. Diagrama prezintă actorii externi şi cazurile de utilizare identificate, numai
din punctul de vedere al actorilor (care este comportamentul sistemului, aşa cum este el perceput
de utilizatorii lui?) nu şi din interior, precum şi conexiunile identificate între actori şi cazurile de
utilizare.

Diagrama claselor (Class Diagram)

O diagramă a claselor prezintă structura fizică a claselor identificate în sistem. Clasele


reprezintă “lucruri” gestionate de sistem; clasele pot fi legate în mai multe moduri: asociate
(conectate între ele), dependente (o clasa depinde/foloseşte o altă clasă), specializate (o clasă este
specializarea altei clase) sau împachetate (grupate împreună în cadrul unei unitaţi). Toate aceste
relaţii se materializează în structura internă a claselor în atribute şi operaţii.

Diagrama este considerată statică, în sensul că este validă în orice moment din ciclul de viaţă al
sistemului.
Diagrama de colaborare (Collaboration Diagram)

Această diagramă surprinde colaborarea dinamică între obiecte, într-o manieră similară cu
a diagramei de secvenţă, dar pe lângă schimbul de mesaje (numit şi interacţiune) prezintă
obiectele şi relaţiile dintre ele (câteodată referite ca şi context).

Dacă cel mai important aspect este timpul sau secvenţa de mesaje vom folosi diagrama de
secvenţă, dar dacă trebuie scos în evidentă contextul, vom apela la o diagramă de colaborare.

Desenarea unei diagrame de colaborare se face similar cu a unei diagrame a obiectelor. Mesajele
vor fi reprezentate prin săgeţi între obiectele implicate în mesaj şi pot fi însoţite de etichete care
specifică ordinea în care acestea vor fi transmise. De asemenea se pot vizualiza condiţii, iteraţii,
valori returnate, precum şi obiectele active care se execută concurent cu alte obiecte active.
O diagramă de colaborare pentru un server de imprimantă.:

Diagrama de secvenţă (Sequence Diagram)

O diagramă de secvenţă prezintă colaborarea dinamică între un număr de obiecte (vezi


figura 6), mai precis secvenţele de mesaje trimise între acestea pe măsura scurgerii timpului.

Obiectele sunt văzute ca linii verticale distribuite pe orizontală, iar timpul este reprezentat
pe axa verticală de sus în jos. Mesajele sunt reprezentate prin săgeţi între linile verticale ce
corespund obiectelor implicate în mesaj. Diagrama de secvenţă pentru un server de imprimantă:
Diagrama de stare (State Diagram)

O stare este de obicei un complement al descrierii unei clase. O diagramă de stare prezintă toate
stările prin care trece un obiect al clasei precum şi evenimentele care-i cauzează modificările de
stare. Modificarea stării se numeşte tranziţie. O diagramă de stare pentru un ascensor:

Diagrama componentelor (Component Diagram)

O diagramă a componentelor prezintă structura fizică a codului în termenii componentelor de


cod, realizând o mapare de la view-ul logic la view-ul componentelor. O componentă poate să
conţină un cod sursă sau poate să fie într-o forma binară sau executabilă. În cadrul diagramei vor
fi ilustrate şi dependenţele dintre componente, ceea ce permite o vizualizare simplă a
componentelor care vor fi afectate de modificarea uneia dintre ele.
Diagrama de desfăşurare (Deployment View)

Arhitectura fizică pe care va fi implementat sistemul, calculatoarele, device-urile (referite


ca nodurile sistemului), împreună cu conexiunile dintre ele, vor putea fi prezentate în cadrul unei
diagrame de desfaşurare. Componentele şi obiectele executabile sunt alocate în interiorul
nodurilor, ceea ce ne va permite o vizualizare a unitaţilor care se vor executa pe fiecare nod. O
diagramă de desfaşurare care prezintă structura fizică a sistemului:
Modelarea cu UML
A modela cu UML înseamnă a construi mai multe modele pentru diferitele faze ale dezvoltării şi
pentru diverse scopuri.

În faza de analiză scopul modelării este să surprindă necesitaţile sistemului şi să modeleze


clasele de bază din “lumea reală” şi colaborările dintre acestea.

În faza de design, este expandat modelul din faza de analiză şi este formulată o soluţie tehnică
luând în considerare caracteristicile mediului în care acesta va fi reprezentat.

În faza de implementare, modelul este transpus în cod iar apoi compilat în programe, pentru ca în
final, în modelul de desfăşurare, să se folosească o descriere care să explice cum sistemul va fi
adaptat arhitecturii fizice concrete.

În mod normal când construim un model sau o simplă diagramă vom începe prin a colecta
informaţii de la clienţi sau de la potenţialii utilizatori ai sistemului. Aceasta fază continuă până
când participanţii nu mai au de adus adaugări sau sugestii modelului de bază. Apoi modelul este
transpus în diagrame conform regulilor impuse de limbajul de modelare, după care urmează un
proces iterativ şi incremental pe parcursul caruia sunt adăugate noi detalii soluţiei şi realizată o
documentare a modelului. În final modelul este verificat, evaluat şi sunt corectate eventualele
deficienţe înregistrate în funcţionalitatea lui, de exemplu lipsuri în funcţionalitate, performanţă
scăzută, preţ ridicat de dezvoltare etc. toate acestea presupunând reluarea paşilor care cauzează
aceste carenţe şi găsirea unor soluţii satisfăcătoare.

Modelarea cazurilor de utilizare


Un caz de utilizare este o tehnica de modelare folosită pentru a descrie ce va face un sistem
nou sau ce face deja un sistem existent. Modelarea cazurilor de utilizare a fost folosită pentru
prima dată de Ivar Jacobson în metodele de modelare OOSE şi Objectory. Scopul urmărit în
acest tip de modelare este descrierea funcţionalităţii sistemului aşa cum aceasta este văzută din
exterior de un număr de actori şi a conexiunilor acestora la cazurile de utilizare furnizate de
sistem. Aşadar, pentru crearea modelului cazurilor de utilizare vor trebui identificaţi actorii,
cazurile de utilizare, relaţiile dintre acestea cât şi relaţiile cu actorii. Toate aceste faze presupun
discuţii cu clienţii şi eventual cu persoanele care reprezintă actorii.

În această fază de modelare sistemul este văzut ca o “cutie neagră”, care trebuie să poată realiza
anumite sarcini, fără a ne interesa cum le face, cum vor fi implementate, sau cum lucrează intern.
Scopul principal al construirii acestui tip de diagramă este:

 Să decidă şi să descrie cerinţele funcţionale ale sistemului, cerinţe care au fost deduse
după o discuţie între client şi/sau utilizatorii sistemului şi viitorii dezvoltatori ai acestuia.

 Să ofere o descriere clară şi consistentă a ce va trebui să facă sistemul, prin urmare


modelul este folosit pentru comunicarea cerinţelor tuturor persoanelor implicate în
construirea sistemului şi să constituie un punct de plecare în realizarea muncii viitoare (alte
modele, design arhitectural, implementarea propriu-zisă).

 Să constituie o bază pentru realizarea testelor de verificare dacă funcţionalitatea finală


a sistemului concordă cu cerinţele iniţiale ale acestuia.

 Să permită o transformare uşoară a cerinţelor funcţionale în viitoare clase şi operaţii.

Diagrama cazurilor de utilizare (Use Case Diagram)


Un model use case este descris folosind una sau mai multe diagrame use case. Acestea
conţin următoarele elemente de modelare: actori, cazuri de utilizare şi diferite relaţii între aceste
elemente: generalizare, asociere, dependenţă.

Actorul

Un actor poate fi orice sau oricine interacţionează cu sistemul, adică trimite sau
recepţionează mesaje de la sistem sau schimbă informaţii cu acesta. Actorul joacă un rol în
cadrul sistemului, nu este un utilizator individual al acestuia, prin urmare reprezintă un tip (o
clasă) nu o instanţă. “Studentul Popescu vrea să împrumute o carte de la bibliotecă”, rolul lui
este de abonat al bibliotecii. Orice mesaj trimite actorul sistemului este un caz de utilizare,
câteodată numit şi stimul.

Un actor poate fi:

 Actor primar, dacă foloseşte funcţionalitatea de bază a sistemului, de exemplu într-un


sistem de bibliotecă, bibliotecarul, sau

 Actor secundar, dacă foloseşte funcţionalitatea secundară, cum ar fi gestionarea unei


baze de date, comunicare, backup şi alte operaţii administrative.

O altă clasificare ar fi în:


 Actori activi, care iniţiază cazurile de utilizare, sau

 Actori pasivi, care participă numai în unul sau mai multe cazuri de utilizare.

Identificarea actorilor

Operaţia de identificare a actorilor revine la a stabili care sunt entităţile interesate de utilizarea
sistemului sau de interacţiunea cu acesta. Pentru aceasta putem să ne folosim de următoarele
întrebări:

 Cine va folosi funcţionalitatea principală a sistemului (aceştia vor fi actorii


principali)?

 Cine va avea nevoie de sistem în munca de zi cu zi?

 Cine va administra şi ţine în stare de funcţionare sistemul (aceştia vor fi actorii


secundari)?

 Ce unităţi (device-uri) hardware vor avea nevoie de sistem?

 Cu ce alte sisteme va interacţiona? Aceste pot fi împărţite în sisteme (sisteme de


calculatoare, aplicaţii) care vor iniţia un contact cu sistemul sau sisteme pe care acesta le
va contacta.

 Cine este interesat de rezultatele (valorile) generate de sistem?

Modul de reprezentare a actorilor în cadrul diagramelor de modelare UML este prezentat în


figura:

Cazuri de utilizare

Un caz de utilizare reprezintă o funcţionalitate completă a sistemului, aşa cum este ea percepută
de un actor. În UML el este definit ca: “un set de secvenţe de acţiuni pe care sistemul le
realizează pentru a furniza o valoare unui actor particular”. Acţiunile pot presupune
comunicarea cu un număr de actori (utilizatori sau alte sisteme) sau realizarea unor calcule în
interiorul sistemului.

Caracteristicile cazurilor de utilizare sunt:

 Un caz de utilizare este iniţiat întotdeauna de un actor; actorul trebuie să ceară direct
sau indirect sistemului realizarea unui caz de utilizare;
 Un caz de utilizare furnizează o valoare unui actor;

 Un caz de utilizare trebuie să fie complet. O greşeală frecvent întâlnită este să


împărţim un caz de utilizare în altele mai mici şi să le implementăm ca apeluri de funcţii în
limbajele de programare. Un caz de utilizare nu este complet până când nu este produsă
valoarea finală, chiar dacă pentru aceasta sunt necesare câteva dialoguri.

Un caz de utilizare este o clasă nu o instanţă a acesteia. Clasa descrie funcţionalitatea ca


un întreg, incluzând alternative posibile, erori şi excepţii care pot să apară pe parcursul execuţiei.
O instanţiere a unui caz de utilizare se numeşte scenariu şi reprezintă o utilizare actuală a
sistemului, de exemplu “Studentul Popescu cere bibliotecarului sa-i facă o rezervare pentru
cartea de UML care în momentul respectiv nu este disponibilă”.

Cazurile de utilizare sunt conectate cu actorii prin asocieri, numite şi asocieri de comunicare. În
mod normal acestea sunt relaţii unu-la-unu nedirecţionate ceea ce înseamnă ca o instanţă actor
comunică cu o instanţă a cazului de utilizare şi că această comunicare este în ambele sensuri.

Identificarea cazurilor de utilizare

Procesul de identificare a cazurilor de utilizare începe de la actorii deja identificaţi. Pentru


fiecare actor se vor pune următoarele întrebări:

 Care sunt funcţiile pe care actorul le aşteaptă de la sistem? Ce trebuie să poată face
actorul?

 Are nevoie actorul să citească, să creeze, să modifice, să distrugă sau să pastreze


anumite tipuri de informaţii în sistem?

 Trebuie să ştie actorul de apariţia unui anumit eveniment în sistem? Ce funcţionalitate


reprezintă aceste evenimente?

 Poate actorul să-şi simplifice munca de zi cu zi sau să lucreze mai eficient folosind
funcţii noi ale sistemului?

Sau alte întrebări care nu presupun un actor curent:

 Ce intrări/ieşiri sunt necesare în sistem? De unde vin acestea şi unde merg?

 Care sunt problemele majore în implementarea curentă a acestui sistem? Poate fi


înlocuit un sistem manual cu unul automat?
Reprezentarea cazurilor de utilizare

Relaţii între cazurile de utilizare

Sunt trei tipuri de relaţii ce pot fi definite între cazurile de utilizare: extindere, utilizare şi
grupare.

Relaţia de extindere

Relaţia de extindere este o generalizare a unui use case prin adăugarea de acţiuni noi. Un
extend poate include comportamentul use case-ului extins, în funcţie de condiţiile de extindere.
Un use case extins poate gestiona excepţiile specifice cazurilor din use case-ul general care nu
sunt uşor de tratat în acesta, sau care apar în sistem pe măsura dezvoltării lui. O relaţie de
extindere între cazuri de utilizare este văzută ca o generalizare (se foloseşte stereotipul
<<extend>>).

O relaţie de extindere. (Săgeata punctează spre use case-ul extins)

Relaţia de utilizare

Când mai multe cazuri de utilizare au un comportament comun, acesta poate fi modelat
într-un singur caz de utilizare şi apoi folosit şi de altele. Dacă use case-ul nu este folosit
niciodată direct se numeşte caz de utilizare abstract. O relaţie de utilizare foloseşte stereotipul
<<uses>>.
Relaţie de utilizare

Dacă mai multe cazuri de utilizare gestionează funcţiuni similare sau sunt într-un fel legate unul
de altul, acestea pot fi grupate în pachete UML. Pachetele nu au un înţeles semantic.

Descrierea cazurilor de utilizare

Descrierea cazurilor de utilizare se face de obicei printr-un text care conţine o specificare
simplă dar consistentă a modului de interacţiune între actori şi cazurile de utilizare ale
sistemului. Aceasta va surprinde comportamentul sistemului şi va ignora modul în care acesta va
fi implementat în sistem.

Descrierea va conţine:

 Obiectivele cazurilor de utilizare;

 Cum este iniţiat un caz de utilizare? Ce actori iniţiază execuţia şi în ce situaţii?

 Care este fluxul de mesaje între actori şi cazurile de utilizare;

 Fluxul alternativ în cazurile de utilizare; Un caz de utilizare poate să aibă o execuţie


alternativă în funcţie de anumite condiţii sau excepţii;

 Când un caz de utilizare este considerat terminat, şi care va fi valoarea transmisă


actorului;

Un caz de utilizare poate fi descris printr-o diagramă de activitate, care va permite


vizualizarea secvenţelor de activitaţi, ordinea lor şi opţional deciziile luate pentru a specifica
operaţia care urmează a fi realizată. Trebuie să reţinem un lucru important: modelul cazurilor de
utilizare trebuie să fie uşor de comunicat utilizatorului/clientului.

După ce au fost descrise cazurile de utilizare vor trebui specificate relaţiile existente între
acestea. Întrebările care vor trebui puse în această fază sunt:

 Toţi actorii implicaţi comunică cu cazuri de utilizare?


 Sunt asemănări între actori, poate fi descrisă o clasă actor de bază?

 Sunt asemănări între cazurile de utilizare existente? Există un flux comun de activitaţi
care să poată fi descris ca o relaţie de utilizare a unui caz de utilizare?

 Există cazuri de utilizare care să poată fi descrise ca extend-uri?

 Sunt actori sau cazuri de utilizare fără asocieri de comunicare? Dacă există aşa ceva
este greşit!

 Sunt cerinţe funcţionale încă necuprinse în cazuri de utilizare? Dacă da, vor trebui
rezolvate.

Cazurile de utilizare sunt folosite şi la testarea sistemului; sunt două tipuri de teste care se pot
realiza: verificarea, în care se confirmă sau nu dacă sistemul a fost dezvoltat corect, în acord cu
specificaţiile cerute şi respectiv validarea, care verifică dacă sistemul construit este util pentru
client şi utilizatorul final.

Modelarea conceptuala
Clase, obiecte şi relaţiile lor
În modelarea orientată-obiect elementele primare de modelare sunt clasele, obiectele şi
relaţiile dintre ele. Când încercăm să descriem un sistem, folosim clase şi obiecte, pentru a
modela ce este în sistem (entităţile) şi relaţii pentru a preciza modul în care acestea sunt
structurate.

Clase şi obiecte
Un obiect este o entitate despre care putem vorbi şi pe care o putem gestiona. Acesta poate
să aparţină lumii reale, de exemplu poate fi o parte a unui tip de sistem: o maşină, o organizaţie,
o afacere, sau să nu existe direct în lumea reală, dar să ne ajute în studiul structurii şi
comportamentului obiectelor lumii reale. Aşadar, într-un fel sau altul obiectele ne ajută la
înţelegerea lumii reale.

O clasă este o descriere a proprietăţilor şi comportamentului unui tip obiect. Toate


obiectele sunt instanţe ale claselor; un obiect joacă un rol similar cu al unei variabile de un
anumit tip într-un limbaj de programare.

Diagrama claselor
Pentru a descrie static un sistem în termenii claselor şi relaţiilor dintre acestea, putem
construi diagrama claselor care constituie totodată şi punctul de plecare în construirea altor
tipuri de diagrame construite pentru a surprinde alte aspecte ale sistemului, cum ar fi stările
obiectelor sau colaborările dintre obiecte.

Identificarea claselor

Pentru identificarea claselor unui sistem putem să ne folosim de următoarele întrebări:

 Avem informaţii care trebuiesc stocate sau analizate? Dacă da, ele sunt posibile
candidate pentru o clasă.

 Avem sisteme externe cu care va comunica sistemul ce-l construim? Dacă da, este
normal să le luăm în considerare când modelam sistemul.

 Avem biblioteci sau componente din proiecte anterioare pe care putem şi dorim să le
folosim? În caz afirmativ acestea conţin clase candidate.

 Sunt device-uri în sistem care vor trebui gestionate? Orice device conectat la sistem
înseamnă o clasă candidat care sa-l gestioneze.

 Avem părţi organizaţionale în sistem? Vom avea nevoie de clase în care să le


implementăm.

 Care sunt rolurile pe care actorii le joacă în sistem? Acestea pot fi văzute ca şi clase,
de exemplu utilizator, client.

Nume clasă

Atribute

Operaţii

Figura 1: O clasă este reprezentată în UML ca un dreptunghi împărţit în

trei compartimente care conţin: numele clasei, atributele şi repectiv operaţiile acesteia.

Compartimentul atributelor

Atributele capturează informaţia care descrie şi identifică o instanţă specifică a unei clase şi
au un tip asociat care poate fi unul din tipurile primitive: integer, Boolean, real, point, area,
enumerare sau orice alt tip, inclusiv alte clase. Pentru un atribut se poate stabili un grad de
vizibilitate: un atribut public (va fi precedat de +) va fi vizibil şi va putea fi folosit în alte clase,
privat (precedat de -) specifică un atribut care poate fi accesat numai în clasa respectivă sau
protejat, care poate fi folosit numai în clasa în care a fost definit şi în generalizările sau
specializările ei.
În general sunt suficiente numai atributele public şi privat, dar dacă e nevoie se pot
specifica şi alte grade de vizibilitate care apar în limbajul în care se va face implementarea.

Dacă un atribut va fi partajat de toate obiectele clasei respective, va fi definit ca atribut al


clasei şi se va reprezenta subliniat. Sintaxa generală pentru descrierea unui atribut este:

vizibilitate nume: tip_expresie = valoare_iniţiala {lista de proprietaţi}

Numele şi tipul sunt obligatorii, celelalte părţi sunt opţionale. Şirul de proprietaţi poate fi
folosit pentru specificarea altor informaţii despre atribute, de exemplu dacă atributul va fi
persistent.

Asigurare
+data:Date= data curentă

+client:String

-administrator:String=”Nespecificat”

-numar de asigurari:Integer = 0;

+starea:Stare=neplatit{neplatit, platit}

Figura 2: O clasă cu domeniul atributelor precizat. Atributele precedate de semnul “+” sunt
publice, cele precedate de semnul “–“ sunt private, iar atributul subliniat este atribut al clasei.

Compartimentul operaţiilor

Operaţiile sunt folosite pentru manipularea atributelor sau pentru realizarea anumitor
acţiuni. Pentru descrierea unei operaţii va trebui specificat tipul rezultat, numele, zero sau mai
mulţi parametrii, adică semnătura operaţiei. Ca şi în cazul atributelor şi pentru operaţii se poate
specifica un grad de vizibilitate care poate fi public (+) sau privat (-). Sintaxa formală pentru
definirea unei operaţii este:

vizibilitate nume (lista_parametrii) : tip_rezultat {sir_de_proprietaţi}

Toate operaţiile trebuie să aibă o semnatură unică în cadrul clasei, iar mulţimea operaţiilor unei
clase descriu funcţionalitatea clasei respective, ce servicii oferă, aşadar pot fi văzute ca o
interfaţă a clasei. La specificarea unei operaţii poate fi precizată o precondiţie, care trebuie să fie
îndeplinită înainte de execuţia operaţiei şi repectiv o postcondiţie, care trebuie să fie îndeplinită
după execuţia ei.

TitluCarte
- titlu: String

- autor : String

- isbn : String
+ titlu()

+ găseşteDupăNume():TitluCarte

+ găseşteDupăAutor():TitluCarte

Figura 3: O clasă cu atributele şi operaţiile specificate

O clasă persistentă are proprietatea că obiectele sale există şi după terminarea


programului. Obiectele persistente sunt stocate fie într-o bază de date, fie în fişiere pe disc, şi de
obicei dispune de operaţii care permit gestionarea obiectelor stocate. Pentru a descrie o clasă
persistentă se va specifica proprietarea {persistent} în compartimentul numelui.

Relaţii
Aşa cum am spus anterior, o diagramă a claselor conţine clase şi relaţiile dintre ele.
Relaţiile pot fi: asocieri, generalizări, dependenţe sau relaţii de rafinare.

Relaţia de asociere

Asocierea este o conexiune între clase, ceea ce înseamnă o legătură semantică între
obiectele claselor implicate în relaţie. În mod normal este o relaţie bidirectională, ceea ce
presupune că dacă un element este asociat cu altul, asocierea există şi în sens invers. Cea mai
întâlnită relaţie de asociere este asocierea normală a cărei reprezentare poate fi văzută în Figura
4. Asocierea are un nume care de obicei este un verb; dacă asocierea este numai într-un sens se
va folosi o săgeată pentru precizarea sensului.

Figura 4:
Relaţia de
asociere. Asocierea se va citi: “Un copil foloseşte un calculator”

Figura 5: Relaţia de asociere. “O persoană are una sau mai multe


maşini, şi o maşină aparţine uneia sau mai multor persoane”

Pentru a preciza numărul de elemente legate (multiplicitatea) folosim un domeniu care


poate fi o construcţie de forma 0..1, însemnând 0 sau 1 obiecte, 0..* sau *, zero la mai multe,
5..11, pentru un număr cuprins între 5 şi 11, sau o înşiruire de numere, de exemplu (1,4,8,9).
Dacă nu este specificată nici o multiplicitate, va fi considerată valoarea implicită, adică 1.

Este posibil să definim o relaţie de asociere recursivă, care înseamnă că o clasă este
conectată la ea însăşi, ca în figura următoare:

Figura 6: O reţea ce conţine mai


multe noduri, fiecare conectat la altul

O asociere poate să aibă roluri asociate fiecărei clase implicate în relaţie. Acestea vor fi
plasate la sfârşitul asocierii cu clasa următoare, ca în figurile următoare:

Figura 7: O
persoană poate
juca rolul de “şofer” şi o maşină rolul de “maşină a firmei”. Rolurile sunt
contexte în care acţionează obiectele. O maşină poate juca un alt rol într-un alt
context, de exemplu poate fi maşină de poliţie, ambulanţă…

Figura 8: Un soţ este


căsătorit cu o soţie. Atât
soţul cât şi soţia sunt
persoane. Dacă o persoană
nu este căsătorită, nu va putea juca rolul de “soţ” sau de “soţie”, ceea ce
înseamnă ca această asociere nu se poate aplica.
Figura 9:
O clasă
poate
juca
roluri
diferite în
asocieri
diferite.
Aici
persoana
poate
juca rolul
de soţ,
soţie sau
asigurat.

Compania joacă rolul de asigurator. O companie (asiguratorul) poate avea mai


multe contracte de asigurare, fiecare contract va fi încheiat cu o persoana
căsătorită. Un contract presupune cel mult o poliţă de asigurare.

Asocierea calificată este folosită în asocieri one-to-many sau many-to-many. Calificarea


specifică modul în care va fi identificat un obiect specific al părţii mai multe (many) a unei
asocieri.

Figura
10: În
clasa
Tablou
asocierea este reprezentată cu o identificare unică pentru fiecare figură (id
figura)

Asocierea OR (asocierea sau) este o constrângere a două sau mai multe asocieri. Ea
specifică faptul ca obiectele clasei pot participa la cel mult o asociere la un moment dat. În unele
modele nu toate combinaţiile sunt corecte, şi aceasta poate cauza unele probleme: de exemplu o
persoană (asiguratul) poate avea un contract cu o campanie de asigurari, iar compania
(asiguratorul), poate avea un contract cu o altă companie, dar între persoana şi a doua companie
nu putem avea acelasi tip de contract de asigurare. O cale de rezolvare ar fi utilizarea în acest caz
a unei asocieri-sau. Pentru reprezentare se foloseşte o linie punctată şi construcţia {or}.
Figura 11: O
asociere-or
arată că numai
una dintre
asocieri este
validă la un
moment dat

Asocierea ordonată

Valoarea implicită pentru o asociere este neordonat, dar dacă avem nevoie de o ordine,
vom putea specifica acest lucru folosind construcţia {ordered} lângă clasa ale cărei obiecte vor fi
ordonate, putându-se eventual specifica şi criteriul de sortare, de exemplu {ordered după timp}

Figura 12: O asociere ordonată

Asocierea ternală

Există cazuri când două sau mai


multe clase sunt asociate între ele; o
rezolvare a acestei situaţii, când numărul
claselor implicate este 3 o constituie
asocierea ternală. În figura 13, un client
(asiguratul) poate să aibă zero sau mai multe contracte de asigurare, fiecare contract este încheiat
cu o companie de asigurare (asiguratorul), materializat într-o poliţă de asigurare. O asociere
ternală se reprezintă printr-un romb, dar nu va avea calificatori şi agregare.
Figura 13: Asocierea ternală

Agregarea este un caz special de asociere care indică o relaţie “întreg-parte”. În general
agregarea este folosită pentru a descrie diferite nivele de abstractizare. Cuvintele folosite pentru
identificarea relaţiilor de agregare sunt: “constă din”, “conţine”, “este parte a”, cuvinte care
sugerează o relaţie “întreg-parte” între clasele implicate. Întrucât agregarea este un tip special de
asociere, multiplicitatea, rolurile şi calificatorii se precizează ca şi în cazul asocierilor.

Figura 14: Relaţia de agregare. O flotă are mai multe nave; se poate renunţa la unele
sau se pot aduce nave noi.

Dacă părţile pot fi “parte” a oricărui întreg, ca de exemplu în figura 15, agregarea se
numeşte partajată. Multiplicitatea pe partea întreg trebuie să fie mai mare decât 1.

Figura 15.
Relaţia de
agregare
partajată. O echipă este compusă din mai mulţi membrii, iar o persoană poate fi
membru în mai multe echipe.

Dacă părţile “traiesc” în interiorul întregului, şi vor fi distruse împreună cu acesta, vom
spune că avem o relaţie de agragare compusă. Multiplicitatea pe partea “întreg” trebuie să fie
(0..1) iar pe partea “parte” poate fi orice interval. Agregarea compusă formează un arbore de
părţi, pe când o agregare partajată formează o reţea. Ca modalităţi de reprezentare se pot alege
oricare din notaţiile de mai jos:
(a)

(b)

(c)

Figura 15: Modalităţi de reprezentare pentru o relaţie de agregare compusă; o


fereastră poate să conţină mai multe meniuri, butoane, liste sau texte.

Relaţia de generalizare

Definiţia generalizarii în UML este: “O relaţie taxonomică (taxonomia este ştiinţa


clasificarii) între un element mai general şi un element specific. Elementul specific trebuie să fie
complet inclus în elementul general, care în plus poate conţine informaţii suplimentare. În locul
unei instanţe a elementului general poate fi folosită o instanţă a elementului specific”. Aşadar
generalizarea, numită deseori şi moştenire, permite elementelor să fie specializate în elemente
noi. Generalizarea se poate folosi numai pentru tipuri, nu şi pentru instanţe (o clasă moşteneşte
de la alta, dar un obiect niciodată nu poate moşteni de la alt obiect). Câteodată i se mai spune
relaţie

“is a” (este un).

Deci generalizarea este o relaţie în care o clasă specifică, numită şi subclasă, moşteneşte
atributele, operaţiile şi toate asocierile de la o altă clasă, superclasă. Atributele şi operaţiile cu
vizibilitate public (sunt precedate de +) în superclasă vor fi publice şi în subclasă, pe când
membrii (atribute sau operaţii) cu vizibilitate privată (precedaţi de semnul -) vor fi moşteniţi, dar
nu vor fi accesibili acesteia. Pentru protejarea atributelor sau operaţiilor de accesul din afara
subclaselor sau superclasei, vom folosi membrii protejaţi (precedaţi de #). Un membru protejat
nu va putea fi accesat din alte clase ci numai din interiorul clasei şi subclaselor ei.

O clasă poate să joace atât rolul de subclasă cât şi de superclasă dacă este cuprinsă într-o
ierarhie de clase. O ierarhie de clase este un graf în care clasele sunt conectate unele cu altele
prin relaţii de generalizare. Aşadar o clasă poate moşteni de la o singură clasă, dar în acelaşi timp
poate fi moştenită de mai multe clase.

Figura 16: Relaţia de generalizare

Dacă mai multe clase au atribute şi comportament comun, acesta poate fi prins în definiţia
unei clase, care apoi va fi moştenită de clasele implicate. Este posibil ca în superclasă să nu fie
implementate toate operaţiile, ci pentru unele din ele (sau pentru toate) să fie specificată numai
semnătura, caz în care operaţia se numeşte abstractă şi va fi specificat acest lucru folosind
construcţia {abstract}.

O clasă care are cel puţin o operaţie abstactă se numeşte clasă abstactă. O clasă abstractă
nu poate fi instanţiabilă. O clasă care moşteneste o clasă abstractă va trebui să implementeze
acele operaţii, în caz contrar şi ea va fi clasă abstractă. De exemplu clasa Vehicul poate să
definească operaţiile
comune tuturor vehiculele:
condus, pornire, oprire.
Toate clasele care o vor
moşteni vor avea aceste
operaţii.
Figura 17: O persoană conduce vehicule. Operaţia este specifică fiecărui tip de
vehicul şi este implementată efectiv în fiecare din clasele care
moştenesc clasa Vehicul.

În opoziţie cu clasele abstracte, clasele concrete vor avea implementări pentru toate
operaţiile. O subclasă poate să redefinească o operaţie moştenită, chiar dacă operaţia nu era
abstractă în superclasă. Aceasta tehnică se numeşte polimorfism. Implementarea actuală va fi
aleasă în funcţie de obiectul căruia i se aplică operaţia. O tehnică comună este să se combine
moştenirea, polimorfismul şi asocierile recursive sau agregările. Un astfel de exemplu este în
figura 18:

Figura 18: Un tablou conţine mai multe figuri, care pot fi cercuri, linii, poligoane
sau grupuri; un grup conţine mai multe figuri. Fiecare figură este responsabilă de
desenarea ei. Pentru desenarea unui grup se vor apela metodele de desenare ale
figurilor din grupul respectiv.

Constrângere ale relaţiei de generalizare

O constrângere asociată unei relaţii de generalizare permite specificarea unor informaţii


relative la modul în care generalizarea va fi folosită în viitor. Sunt predefinite următoarele
constrângeri pentru generalizarea cu mai mult de o clasă:

 Generalizarea suprapusă (Overlapping Generalization) - este o relaţie prin care o


clasă moşteneşte de la mai mult decât o subclasă, un exemplu este prezentat în figura 19:
Figura 19: Clasa Amfibie va moşteni de la ambele clase.

 Generalizarea desparţită (Disjoint Generalization) – este în opoziţie cu generalizarea


suprapusă, ceea ce înseamnă că subclaselor nu le este permisă specializarea într-o clasă
comună. Aceasta este forma de moştenire implicită.

 Generalizarea completă – este definită atunci când alte generalizări ale superclasei nu
se mai pot face; un exemplu este prezentat în figura 20:

Figura 20: O generalizare este constrânsă să fie completă, aşadar


nici o altă subclasă a clasei Persoana nu se va mai putea adăuga;

 Generalizarea incompletă – este generalizarea implicită, în care nu există restricţii cu


privire la numărul de subclase ale unei superclase;

Relaţia de dependenţă

Relaţia de dependenţă este o conexiune semantică între două elemente de modelare, care pot fi
clase, pachete, cazuri de utilizare, unul independent şi altul dependent. Orice modificare a
elementului independent va fi reflectată şi asupra elementului dependent. Putem avea o relaţie de
dependenţă de exemplu în cazul în care o clasă foloseşte ca parametru un obiect al altei clase, sau
o clasă accesează un obiect global al altei clase, sau o operaţie a unei clase este apelată într-o altă
clasă. În toate aceste cazuri avem o relaţie de dependenţă între cele două clase implicate, cu toate
că nu este o asociere explicită între ele. Modul de reprezentare este specificat în Figura 21.
Pentru relaţie se poate specifica şi o etichetă, care este un stereotip ce identifică tipul de
dependenţă.

Figura 21: Relaţia de dependenţă. O dependenţă “friend” este una în


care un element model oferă altuia un acces special la structura sa
internă. (este preluat din C++)

Relaţia de rafinare
O relaţie de rafinare este stabilită între două descrieri ale aceluiaşi lucru, dar la nivele de
abstractizare diferite. De exemplu putem defini o astfel de relaţie între un tip şi o clasă care-l
implementează, caz în care relaţia se numeşte realizare, sau între o clasă de analiză şi o clasă de
design care modelează acelaşi lucru, sau între o descriere de nivel înalt şi o descriere de nivel
scăzut, iar modul de reprezentare este specificat în figura 22.

Figura 22: Relaţia de


rafinare.

Rafinarea este folosită în coordonarea modelării deoarece permite vizualizarea modului în care
sunt legate modelele din diferite niveluri de abstractizare sau modelele din diferite faze de
modelare.

Reguli. Constrângeri şi derivaţii


Constrângerile sunt folosite pentru a restricţiona un model, pe când derivaţiile sunt reguli despre
cum se pot obţine anumite lucruri plecând de la altele, de exemplu vârsta unei persoane poate fi
dedusă folosind informaţia relativă la data naşterii şi data curentă din sistem.

Regulile pot fi ataşate oricărui element de modelare, dar sunt utile în special pentru atribute,
asocieri, moşteniri sau constrângeri de timp în modele dinamice. Toate regulile vor fi prinse între
acolade.

Atributele pot să aibă constrângeri, de exemplu necesitatea ca un atribut să ia valori într-un


interval, sau să fie derivate, de exemplu calculate pe baza unei formule de calcul specificată
între acolade. Un atribut derivat începe cu slash “/” şi nu va fi stocat în obiectele clasei
respective, ci va fi calculat de fiecare dată (Figura 23).

Figura 23: Un atribut derivat într-o clasă

Relaţiile de asociere pot fi şi ele derivate; de exemplu, dacă o companie are contracte cu mai
mulţi clienţi şi câţiva dintre ei sunt consideraţi mai importanţi (VIP), avem o asociere derivată
care merge de la clasa companie la clasa client reprezentată în Figura 24:
Figura 24: VIP este o asociere derivată

O constrângere pentru o asociere poate fi stabilită de exemplu când o asociere este un subset al
altei asocieri.(vezi Figura 25)

Figura 25: O asociere constrânsă. Asocierea lider de partid al este


un subset al asocierii membru al.

O generalizare poate să aibă numai constrângeri, nu şi derivaţii. O constrângere pentru o relaţie


de generalizare ar fi generalizarea suprapusă, despărţită, completă şi respectiv incompletă,
noţiuni prezentate anterior în acest capitol. Mai sunt de asemenea şi constrângeri pentru timp,
care vor fi prezentate în capitolele următoare.

Interfeţe
Interfeţele joacă un rol important în construirea sistemelor bine structurate. O interfaţă
conţine numai operaţii abstracte, de fapt un număr de semnături care împreună specifică un
comportament comun al tuturor elementelor care aleg să implementeze acea interfaţă.
Echivalentul în limbajele de programare este OLE/COM sau interfeţele Java, unde o interfaţă
poate fi specificată separat de orice clasă specifică, şi un număr de clase pot să aleagă să
implementeze acea interfaţă.

Interfaţa este reprezentată în UML printr-un cerc (vezi Figura 26) , iar conectarea între
interfaţă şi elementul de modelare care o implementează este reprezentată printr-o săgeată
punctată. Clasa este dependentă numai de operaţiile specifice interfeţei nu şi de alte clase.

Figura 26: Clasa A implementează interfeţele Runnable şi Storable. Clasa C


implementează interfaţa Storable. Clasa B foloseşte interfeţele Runnable şi
Storable din A şi interfaţa Runnable din C. Interfeţele sunt specificate ca şi
clase cu stereotipul <<interface>> şi conţin operaţii abstracte care vor trebui
implementate de clasele care le implementează.

Pachete
Un pachet este un mecanism de grupare cu care pot fi legate toate tipurile de elemente de
modelare. În UML un pachet este definit ca: “Un mecanism general de organizare a elementelor
în grupuri legate semantic”. Pachetul luat singur nu are un înţeles. Un pachet este proprietarul
elementelor de modelare pe care le conţine; aşadar acelaşi element de modelare nu va putea fi
prins în mai multe pachete. În schimb, pachetele pot importa elemente de modelare din alte
pachete, iar după import îl va referi ca şi când ar fi proprietatea lui.

Ca şi în cazul altor elemente de modelare putem stabile relaţii între pachete, dar numai
între tipuri, nu şi între instanţe, deoarece pachetele nu au semantica definită de propriile instanţe.
Relaţiile care se vor putea
defini sunt: dependenţa,
rafinarea şi generalizarea.

Figura 27:
Subsistemul E
este dependent
de subsistemul
B, subsistemul
C este dependent de subsistemele B şi D. Subsistemele B,C şi E sunt în
subsistemul A. Toate subsistemele sunt reprezentate ca pachete.

Figura 27:
Subsistemele D şi
E sunt specializări
ale subsistemului
C. Subsistemele B,
C, D şi E sunt în
subsistemul A.
Subsistemul C
depinde de B (are
importate
elemente din el).

Un pachet poate să aibă vizibilitate exact ca şi clasele prin care putem preciza cum alte pachete
pot să-i acceseze conţinutul. În UML sunt patru grade de vizibilitate:

• public (implicit) – alte elemente pot să vadă şi să folosească conţinutul pachetului,


• privat – elementele pachetului pot fi folosite numai în interiorul pachetului sau în
pachetele care-l importă;
• protected – pachetele care moştenesc pot folosi elemente din pachetul generalizat ;
• implementare – este similar cu privat, dar elementele de modelare care au o
dependenţă cu un alt pachet nu pot folosi elemente din interiorul pachetului. Importul
dintr-un pachet este descris ca o dependenţă (cu stereotipul <<imports>>), ceea ce
înseamnă că dacă un pachet are vizibilitatea implementare, nici un alt pachet nu poate
importa din acesta.

Un pachet poate să aibă o interfaţă care-i specifică comportamentul. Un exemplu de interfaţă este
în Figura 28
:

Figura 28: Pachetul X conţine clasele P şi S. Pachetul A are o interfaţă I.


Clasa S , din interiorul pachetului X este dependentă de interfaţa I a
pachetului A.

Modelarea dinamică
Toate sistemele au o structură statică şi un comportament dinamic, iar UML dispune de
diagrame care permit surprinderea şi descrierea ambelor aspecte. Diagramele de clasă exprimă
cel mai bine structura statică a unui sistem (clasele, obiectele şi relaţiile dintre ele), dar nu
ilustrează modul în care acestea cooperează pentru gestionarea taskurilor şi pentru realizarea
funcţionalităţii sistemului; pentru aceasta avem la dispoziţie diagramele de stare, secvenţă,
colaborare şi activitate. Pe lângă structura statică şi comportamentul dinamic, pentru
caracterizarea completă a sistemului avem nevoie şi de funcţionalitatea acestuia, pe care o putem
analiza folosind diagramele cazurilor de utilizare.

Interacţiuni între obiecte


În programarea orientată obiect o interacţiune între două obiecte este realizată printr-un
mesaj trimis de la un obiect la altul. Cel mai adesea mesajul este implementat ca un simplu apel
de operaţie; după ce operaţia a fost executată, controlul este returnat apelantului împreună cu
valoarea returnată. Un mesaj poate fi trimis printr-un mecanism de comunicare peste reţea sau în
interiorul aceluiaşi calculator şi poate fi:

 simplu- folosit când nu sunt cunoscute detaliile de comunicare sau când acestea nu
sunt considerate relevante în diagramă. Acest tip de mesaj se mai foloseşte pentru a vedea
rezultatul unui mesaj sincron. Sensul săgeţii este de la obiectul care iniţiază mesajul spre
apelat (sugerează controlul este trimis înapoi)

 sincron- un flux de control încuibărit este implementat de obicei ca un apel de


operaţie. Operaţia care gestionează mesajul este definită complet înainte de începerea
execuţiei. Rezultatul poate fi văzut ca un mesaj simplu, sau poate fi stabilit implicit la
definirea mesajului.

 asincron- în cazul în care rezultatul unui mesaj nu este trimis explicit apelantului şi
când acesta continuă execuţia după ce mesajul a fost trimis fără a mai aştepta rezultatul
acestuia. În general mesajele de acest tip sunt folosite în sistemele de timp real în care
obiectele se execută concurent.

Mesajele simple şi sincrone pot fi combinate şi reprezentate printr-o singură linie, la un capăt
simbolul mesajului sincron şi la celălalt simbolul mesajului simplu. (vezi figura 1)

Figura 1: Notaţii pentru tipurile de mesaje

Diagrame de stare
Diagramele de stare au rolul de a captura ciclul de viaţă al obiectelor, subsistemelor şi
sistemelor, prin specificarea stărilor în care se poate găsi un obiect şi a evenimentele (mesaje
primite, erori, condiţii care devin adevărate) care-i afectează starea de-a lungul execuţiei. O
diagramă de stare poate fi ataşată oricărei clase care are stări clar identificabile şi un
comportament complex.

Stări şi tranziţii

Orice obiect are o stare; starea este rezultatul unor activităţi anterioare realizate de obiect şi
de obicei este determinată de valorile atributelor şi de legăturile lui cu alte obiecte. Exemple de
stări ale obiectelor:

 O factură (obiect) este neplătită (stare).

 Un ascensor (obiect) staţionează (stare).

Starea unui obiect se modifică când se întâmplă ceva: apare un eveniment - de exemplu
cineva plăteşte o factură, sau pune ascensorul în mişcare. Sunt două dimensiuni ale dinamicii:
interacţiunea cu obiectul şi modificările survenite în starea lui internă, iar pentru a vedea cum
obiectele reacţionează la evenimente şi ce modificări implică fiecare eveniment în starea lor
internă, avem la dispoziţie diagramele de stare. De exemplu, o factură achitată va trece din
starea “neplătit” în starea “plătit” (vezi diagrama din Figura 2)

Figura 2: O diagramă de stare. indică punctul de start (crearea obiectului)


iar punctul de stop (distrugerea obiectului). O stare a unei diagrame se
reprezintă printr-un dreptunghi cu colţurile rotunjite.

O diagramă de stare poate să aibă un punct de start (o stare initială) şi zero sau mai multe
puncte de stop (stare finală). Între stările obiectului sunt stări de tranziţie care pot fi etichetate cu
numele evenimentului care cauzează trecerea în starea respectivă.

Pentru definirea unei stări pe lângă pentru numele stării (de exemplu: “plătit”) se pot
preciza variabile (atribute) iar câteodată este utilă folosirea unor variabile temporare, de
exemplu: contor şi activitate, unde vor fi specificate evenimente sau acţiuni.

Figura 3: Structura unei stări;

Sunt trei tipuri de evenimente standard care pot fi folosite pentru precizarea activităţii:

 entry – acţiunea care se realizează când obiectul intră în starea respectivă (de exemplu
modificarea valorii unui atribut sau trimiterea unui mesaj);

 exit - acţiunea care se realizează când obiectul iese din starea respectivă;

 do - acţiunea care se realizează când obiectul se găseşte în starea respectivă (de


exemplu, trimiterea unui mesaj sau realizarea unui calcul).

Acestea sunt evenimente standard şi nu pot fi folosite în alte scopuri decât cele stabilite pentru
fiecare din ele. Sintaxa formală pentru construcţiile care apar în compartimentul de activitate
este:

nume_eveniment lista_argumente / expresie_actiune


unde nume_eveniment poate fi orice eveniment inclusiv cele standard, în expresie_actiune se va
specifica acţiunea care trebuie să fie realizată (de exemplu: apeluri de operaţii, modificări ale
valorilor atributelor).

Evenimentele standard nu au argumente, dar în general pentru alt eveniment care se


defineşte se poate specifica o listă cu argumente.

În mod normal un eveniment are ataşat o stare tranzacţională care va fi realizată când se
declanşează evenimentul respectiv. Dacă starea tranziţională nu este specificată, starea actuală va
fi modificată când se vor executa acţiunile interne din starea sursă (dacă sunt astfel de acţiuni; de
exemplu, acţiuni standard sau acţiuni definite de utilizator).

Sintaxa formală de specificare a unei stări de tranziţie este:

semnatura_eveniment [conditie_de_garda ] / expresie_actiune ^ clauza_de_trimitere

unde semnatura_eveniment are sintaxa:

nume_eveniment ( parametru , …)

iar clauza de trimitere este de forma:

expresie_destinatie . nume_eveniment_destinatie ( argument , …)

unde expresie_destinatie este o expresie care evaluează un obiect sau un set de obiecte.

Figura 3: Diagrama de stare pentru un ascensor. Ascensorul porneşte de la


parter şi poate fi mutat în sus sau jos. Dacă staţionează pe un anumit nivel un
interval de timp este mutat la parter. Diagrama nu are stare finală.
Figura 4: O stare tranziţională între "Staţionează” şi “La parter” are o condiţie
şi o acţiune care va fi executată. Când atributul timp va fi egal cu timp scurs
aceasta va fi executată şi starea va fi schimbată din “Staţionează” în “La
parter”.

Evenimente

Un eveniment este ceva ce se întâmplă şi poate cauza o anumită acţiune, de exemplu


apăsăm butonul în lift (eveniment) şi liftul urcă (acţiune). Când există o legătură bine stabilită
între un eveniment şi o acţiune, aceasta se numeşte cauzalitate. În software engineering, în mod
normal modelăm sisteme cauzale, în care evenimentele şi acţiunile sunt conectate fiecare cu
fiecare. Când nu avem o legătură de cauzalitate? De exemplu, dacă conducem cu viteză mare o
maşină pe şosea s-ar putea să ne oprească poliţia dar nu e sigur că acest lucru se va întâmpla.
Aşadar nu e o conexiune bine stabilită între eveniment (faptul că rulăm cu viteză) şi acţiune (ne
opreşte poliţia).

În UML sunt următoarele tipuri de evenimente:

 O condiţie devine adevărată; Aceasta apare ca o condiţie de gardă într-o stare de


tranziţie;

 Se recepţionează un semnal de la un alt obiect; Semnalul este el însuşi un obiect.


Acesta apare ca o semnătură de eveniment într-o stare de tranziţie. Acest tip de eveniment
se numeşte mesaj.

 Se recepţionează un apel de operaţie de un alt obiect (sau de obiectul însuşi). Acest


tip de eveniment este numit tot mesaj, şi apare în semnătura unui eveniment dintr-o stare
de tranziţie.
 Scurgerea unui interval de timp, de obicei de la apariţia unui alt eveniment, sau a unei
perioade de timp stabilite independent de celelalte evenimente. O astfel de condiţie apare
ca o expresie de timp într-o stare de tranziţie.

Evenimentele sunt declanşatori care activează o stare de tranziţie (chiar dacă activează mai
mult decât una, va fi declanşată numai o stare de tranziţie) şi sunt procesate o singură dată. Dacă
apare un eveniment şi condiţia din starea de tranziţie este falsă, evenimentul este ignorat şi nu va
fi stocat pentru o viitoare revenire când condiţia va fi adevărată.

O clasă poate recepţiona sau trimite mesaje care sunt apeluri de operaţii sau semnale
(ambele tipuri folosesc semnătura evenimentului). La un apel al unei operaţii, va fi executată şi
se va produce un rezultat. Când este trimis un obiect semnal, cel care-l recepţionează “prinde”
obiectul şi-l foloseşte.

Semnalele sunt clase ordinare care pot fi folosite numai pentru trimiterea semnalelor.
Clasele semnal pot fi stereotipizate cu <<signal>>. Se poate construi şi o ierarhie de semnale,
aşadar dacă o stare de tranziţie are o semnătură de eveniment care specifică un anumit semnal,
toate subsemnalele vor putea fi recepţionate prin aceeaşi specificare (vezi Figura 5).

Şi erorile sunt evenimente şi pot fi utile în procesul de modelare. În UML nu există un


suport explicit pentru erori, dar pot fi modelate ca evenimente stereotipizate, de exemplu:

<<error>> out_of_memory
Figura 5: O ierarhie de clase semnal, cu o superclasă abstractă. Diagrama de
stare din partea dreaptă recepţionează semnale de intrare (subsemnale ale
clasei Input). Pot fi transmise numai semnale concrete deoarece semnalele
abstracte nu pot fi instanţiabile.

Comportamentul claselor poate fi specificat fie prin operaţii (algoritmi) fie explicit în diagramele
de stare, fie în amândouă. Când diagramele de stare sunt implementate în limbaje de programare
orientate obiect, operaţiile sunt implementate direct în algoritmi, folosind comenzi case, sau cu
mecanisme separate, ca de exemplu tablele de funcţii.. UML nu dă nici o recomandare despre
modul în care să fie implementate evenimentele semnal în limbajele de programare, dar de obicei
sunt implementate ca şi clase cu atribute şi operaţii.

Clasele care vor recepţiona semnale vor trebui să aibă o operaţie corespunzătoare care
recepţionează obiectul semnal ca argument. De exemplu, diagrama de stare pentru un ceas
digital este:

Figura 6: Diagrama de stare pentru un ceas digital.

Diagrama de secvenţă
Diagramele de secvenţă descriu modul în care obiectele interacţionează şi comunică între
ele. Atenţia în aceste diagrame ne va fi focalizată asupra secvenţelor de mesaje, mai precis ce
mesaje sunt trimise şi recepţionate de obiecte. Diagramele de secvenţă au două axe: timpul, axa
verticală şi setul de obiecte pe axa orizontală.

Fiecare obiect este reprezentat într-un dreptunghi cu numele obiectului sau clasei subliniat. O
linie punctată, “linia vieţii”, indică execuţia obiectului de-a lungul secvenţei (mesajele trimise
sau recepţionate şi activarea obiectului). Comunicarea între obiecte este reprezentată prin linii de
mesaj verticale între liniile vieţii obiectelor. În aceste diagrame mesajele vor putea fi sincrone,
asincrone sau simple, ca şi în cazul diagramelor de stare. Fiecare mesaj poate avea

 O semnătură - cu numele şi parametrii lui, de exemplu: Print (file:File)


 un număr de secvenţă prin care poate fi de asemenea să fie referit;

 condiţii, prinse între acolade; o condiţie trebuie să fie adevărată pentru ca un mesaj să
poată fi trimis sau recepţionat.

 rezultatele mesajelor sincrone, ca de pildă apelurile de operaţii sunt reprezentate printr-


o săgeată simplă, dar rezultatele nu sunt vizibile;

Diagramele de secvenţă pot fi utilizate în două forme: forma generică (generic form), în
care sunt descrise toate alternativele posibile dintr-un scenariu, ramuri, condiţii, cicluri şi forma
instanţă (instance form), care descrie un scenariu în detaliu, documentează o interacţiune
posibilă; aceasta nu are condiţii, cicluri, arată numai interacţiunea în scenariul ales. Un exemplu
de scenariu este “deschiderea unui cont”; diagrama de secvenţă care foloseşte forma generică va
descrie toate alternativele posibile: când o anumită operaţie se execută cu succes, când clientul
nu poate să deschidă contul, când sunt banii depozitaţi în cont ş.a.m.d. acelaşi scenariu descris în
forma instanţă va trebui să aleagă o execuţie specifică, de exemplu o diagramă poate să trateze
cazul în care contul este deschis cu succes.

Un mesaj este o comunicare între obiecte. Recepţionarea unui mesaj este considerată în mod
normal un eveniment. Mesajele pot fi semnale, apeluri de operaţii sau ceva similar, de exemplu
RPC (Remote Procedure Call) în C++ sau RMI (Remote Method Invocation) în Java. Când
mesajul este recepţionat, în obiectul care-l receptează este iniţiată o activitate, numită activare.
Figura 6: Conceptele folosite într-o diagramă de secvenţă. Mesajul de la
serverul de imprimantă la imprimantă are o condiţie care arată ce alternative
sunt descrise în diagrama de secvenţă. Fie mesajul este trimis imprimantei, fie
este stocat în coada de aşteptare a imprimantei;

Etichete care definesc iteraţii şi constrângeri

O diagramă de secvenţă poate să aibă etichete (orice tip de marcări de timp,


descrieri ale acţiunilor, constrângeri ş.a, vezi Figura 7) şi comentarii pe marginea stângă
sau dreaptă

Figura 7: Utilizarea etichetelor pentru specificarea constrângerilor de timp. Timpul


între a şi b nu trebuie să fie mai mare de 5 secunde iar mesajul Print de la server
trebuie recepţionat în cel mult o secundă. Săgeata înclinata arată că timpul între
trimiterea şi recepţionarea mesajului este important. De obicei constrângerile sunt
în interiorul acoladelor.

Crearea şi distrugerea obiectelor

Diagramele de secvenţă pot arata ce obiecte sunt create sau distruse. Un obiect poate fi creat de
un altul printr-un mesaj care în mod normal este sincron; Obiectul nou creat va fi plasat în locul
în care este creat. Când un obiect este distrus, va fi marcat cu un X mare, iar linia vieţii se va opri
în locul unde a fost distrus (vezi figura 8).
Figura 7:
Mesajul
Client
creează un
nou obiect
al clasei
Client.
Operaţia
ŞtergeClient
elimină un
obiect
Client.
Rezultatul
creării sau
distrugerii
poate fi
văzut
explicit dar
nu în
aceasta
diagramă.

Recursivitatea

Recursivitatea este o tehnică folosită de mulţi algoritmi, şi apare când o operaţie se apelează pe
ea însăşi. Mesajul este întotdeauna sincron şi este marcat ca şi în diagrama de secvenţă.
Rezultatul este văzut ca un simplu mesaj.

Figura 8: operaţia() se
va apela pe ea însăşi.
Va trebui să existe o
condiţie în operaţie
care să oprească la un
moment dat
recursivitatea.

Diagramele de colaborare
În diagramele de colaborare vom urmări atât
interacţiunile cât şi legăturile între un set de obiecte care colaborează. Atât diagramele de
secvenţă cât şi cele de colaborare vizualizează interacţiuni, dar diagrama de secvenţă ia în
considerare timpul, pe când cea de colaborare, spaţiul. Ca şi diagramele de secvenţă şi cele de
colaborare pot fi folosite pentru a ilustra execuţia unei operaţii, a unui caz de utilizare sau a unui
scenariu de interacţiune într-un sistem. În acest

Figura 9: Un Actor trimite un mesaj Print unui Calculator. Acesta trimite


un mesaj Print Serverului de Imprimantă, care trimite mesajul Imprimantei,
dacă aceasta este liberă.

O etichetă asociată unui mesaj într-o diagramă de colaborare are sintaxa:

predecesor conditie_de_garda expresie_secventa valoare_returnata := semnatura

unde

 predecesor este o expresie pentru sincronizarea thread-urilor, ceea ce înseamnă că mesajele pentru
specificarea numerelor de secvenţă trebuie să fie realizate şi gestionate înainte ca mesajul curent să fie trimis
(execuţia este continuă). În lista, numerele de secvenţă sunt separate prin virgula.

 conditia_de_garda este prinsă între paranteze drepte

 numărul de secvenţă specifică ordinea mesajelor. Mesajul 1 va începe întotdeauna secvenţa de mesaje;
Primul tratat când începe gestionarea mesajului 1 este mesajul 1.1, 1.2, 1.2.1, s a m d

Recurenţa reprezintă o execuţie condiţională sau iterativă. Sunt două posibilităţi:

1. * [ clauza_de_iterare ] - folosită pentru specificarea iteraţiei (execuţia repetată). Între paranteze


drepte este prinsă condiţia de iterare, de exemplu [i: =1..n] . Presupunem că avem o etichetă de mesaj care
conţine o iteraţie; aceasta poate fi:

*[x= 1..10 ] : executaCeva()

2. [ clauza_conditie ] – este folosită de obicei pentru specificarea ramurilor, nu


pentru condiţii de gardă.

De exemplu, [x>0] şi [x<0] sunt două clauze-condiţii care pot fi folosite pentru ramificare,
când numai una din condiţii este adevărată, aşadar numai una din ramuri va fi executată.. Atât
clauza_condiţie cât şi clauza de iterare pot fi exprimate în pseudo-cod sau într-un limbaj de
programare.
Valoarea returnată va fi asignată unei semnături de mesaj. O semnătură este compusă din
numele mesajului şi o listă de argumente. Valoarea returnată este valoarea obţinută ca rezultat al
apelului operaţiei (un mesaj). Un exemplu este eticheta mesaj: 1.4.5: x:=calc(n), din figura 10:

Figura 10: Iteraţia şi valoarea returnată văzute într-o diagramă de colaborare;

Alte exemple de etichete de mesaje sunt:

1: display()

[mode = display] 1.2.3.7:redraw()

2 *[n:=1..z]: prim :=nextPrim (prim)

3.1 [x<0]: foo()

3.2 [x>=0]: bar()

1.1a,1.1b/1.2: continue()

Timpul de viaţă al unui obiect

Obiectele create pe parcursul colaborării sunt descrise cu {new}, obiectele distruse cu


{destroy}, iar obiectele care sunt atât create cât şi distruse în aceeaşi colaborare sunt descrise cu
{transient}, care este echivalentul unui {new} {destroy}. Un exemplu poate fi văzut în figura 11:

3.1: Actualizare(data)
Figura 11: Obiectul FereastraPrincipală recepţionează mesajul ClientNou() si,
dacă este memorie liberă, crează un obiect Client. Apoi este creat un obiect
FereastraClient şi obiectul Client este transmis la FereastraClient, în care se
vor putea modifica datele clientului.

Utilizarea diagramelor de colaborare

Diagramele de colaborare pot fi folosite pentru a ilustra interacţiuni complexe între obiecte. Spre
deosebire de diagramele de secvenţă, cele de colaborare ilustrează obiectele şi legăturile dintre
ele: o reţea de obiecte care colaborează şi care în multe situaţii pot face mai uşoară înţelegerea
interacţiunilor. Când trebuie să decidem ce tip de diagramă folosim pentru a ilustra o anumită
interacţiune, regula generală ar fi să alegem diagrama de colaborare când o vizualizare a
obiectelor şi legăturilor dintre ele ne facilitează înţelegerea interacţiunilor şi să alegem o
diagramă de secvenţă numai când avem nevoie să vizualizăm o secvenţă de acţiuni.

Diagramele de activitate
Diagrama de activitate este o variantă al diagramei de stare şi are un scop puţin diferit,
acela de a captura acţiunile şi rezultatele lor. De fapt este o cale alternativă de descriere a
interacţiunilor, cu posibilitatea de specificare a acţiunilor care se vor realiza: ce fac acestea?
(modificările stărilor obiectului), când au loc? (secvenţa de acţiuni) şi unde au loc?

Diagrama de activitate poate fi folosită în mai multe scopuri:

 Pentru a ilustra acţiunile care vor fi realizate când este executată o operaţie. Acesta
este şi cel mai comun caz când apelăm la acest tip de diagramă.

 Pentru a captura munca internă a unui obiect.

 Pentru a arăta ce set de acţiuni legate pot fi realizate şi cum vor afecta acestea
obiectele din jur.

 Pentru a arăta cum o instanţă a unui caz de utilizare poate fi realizat în termenii
acţiunilor sau modificărilor intervenite în starea obiectului.

 Pentru a ilustra cum este organizată munca actorilor, care este organizarea şi obiectele
folosite.

Acţiuni şi tranziţii

O acţiune este realizată pentru a obţine un rezultat. Implementarea unei operaţii poate fi
descrisă ca un set de acţiuni legate, care mai târziu vor fi translatate în linii de cod.
O diagramă de activitate ne permite să vizualizam acţiunile şi relaţiile dintre acestea şi
poate să aibă un punct de start şi un punct de stop, a căror reprezentare poate fi văzută în figura
12:

Figura 12: Acţiunea porneşte când cineva apelează operaţia


AfiseazaTotiClientii() a clasei FereastraClient. Mai întâi este afişat un mesaj pe
ecran, a doua acţiune este crearea unui fişier postscript, a treia este trimiterea
acestuia la imprimanta iar ultima, ştergerea ferestrei de pe ecran. Tranziţiile
sunt automate şi apar de îndată ce este realizată acţiunea în starea sursă.

Acţiunile (stările acţiune) din diagrama de activitate sunt reprezentate prin dreptunghiuri
cu colţurile rotunjite în care poate să apară un text prin care se specifică rolul (ce face)
respectivei acţiuni. Tranzacţiile între acţiuni au aceeaşi sintaxă ca şi în cazul diagramelor de
stare, singura excepţie o constituie evenimentele, care vor putea fi ataşate numai de la punctul de
start la prima acţiune. Tranzacţiile între acţiuni sunt reprezentate prin săgeţi şi pot să aibă condiţii
de gardă, clauze de trimitere şi o expresie acţiune. De multe ori însă nu au nimic specificat, ceea
ce înseamnă că se vor declanşa imediat ce toate activităţile din acţiune vor fi realizate. (vezi
Figura 13)

Figura 13: Tranzacţia între acţiunea a doua şi a treia are o clauză de


trimitere care expediază mesajul Print(fisier) obiectului Printer.

Tranzacţiile sunt protejate de condiţiile de gardă, care au aceeaşi sintaxa ca în cazul diagramelor
de stare şi care vor trebui să fie adevărate pentru ca tranziţia respectivă să fie declanşată. În
Figura 14 avem un exemplu de punct de decizie, reprezentat printr-un romb. Simbolul de decizie
poate să aibă una sau mai multe tranzacţii de intrare şi două sau mai multe tranzacţii de ieşire.
Figura 14: Dacă nu este spatiu pe disc, va afişa pe ecran mesajul “Disc Full”, în
caz contrar mesajul afişat va fi “Printing”.

O tranziţie poate fi împărţită în două sau mai multe tranziţii care pot rezulta în acţiuni paralele.
Acţiunile sunt executate concurent, dar pot fi executate şi una câte una. Cel mai important lucru
este ca tranziţiile să fie toate terminate până când vor fi unite. Linia îngroşata din Figura 15 arată
cum o tranziţie este împărţită în câteva ramuri şi respectiv cum sunt unite ramurile respective.
Figura 15: În urma apelului operaţiei Op() prima acţiune este A. Apoi pot
fi realizate acţiunile B şi C concurent sau pe rând.

S-ar putea să vă placă și