Sunteți pe pagina 1din 42

Diagrame de clasă şi de

obiecte
- Concepte, exemple -
Studiu de caz: Sistem de rezervare (booking) a biletelor de avion
pentru o agenţie de voiaj (varianta simplificată)

Cunoştinţele experţilor în fenomen se pot concretiza în propoziţiile:


Pasul 1. Modelarea propoziţiilor 1 şi 2

Clase: AirlineCompany şi Flight

Obs. Se preferă multiplicitatea 1..* în loc de 0..*, pentru că se iau în


considerare doar companiile care oferă cel puţin un zbor.
Noţiunile open şi close sunt concepte dinamice. Ele privesc schimbările în
starea unui obiect Flight prin ordinul altui obiect AirlineCompany.

Se va insera un atribut state, de tip enumerare, ilustrat în figura de mai jos:

Obs1. Soluţia de mai sus nu e totuşi cea mai fericită. De aceea noţiunea de
stare (state) va fi modelată cu ajutorul diagramelor de stare (state
diagram).
Obs2. În diagramele de clasă, singurele elemente dinamice se realizează
prin intermediul operaţiilor.
(continuare)

Mesajele vor circula între obiectele ce reprezintă instanţe ale claselor,


astfel:
Pasul 2. Modelarea propoziţiilor 6, 7 şi 10

Obs. Se respectă principiul: “if we can ask an element for its value only, it
concerns a simple attribute; if several questions apply to it, though, an
object that possesses several attributes itself is involved, as well as links
with other objects”.
Obs. Deoarece noţiunea de airport e complexă şi implică nu doar un nume,
ci şi capacitate etc, e de preferat să se creeze clasa Airport decât
atributele DepartureAirport şi ArrivalAirport în clasa Flight.

Obs. E necesară restricţia {ordered} la clasa Airport, pentru a indica că


cele două aeroporturi legate zborului sunt ordonate (cel de sosire e după
cel de plecare).
(continuare)

O soluţie tentantă ar fi să se creeze două subclase din clasa Airport:

Obs. Soluţia e incorectă, deoarece fiecare aeroport e un aeroport de


plecare pentru anumite zboruri şi aeroport de sosire pentru alte zboruri,
prin urmare clasele DepartureAirport şi ArrivalAirport au aceleaşi instanţe.
(continuare)

Se va folosi noţiunea de rol, care se potriveşte perfect situaţiei:


Obs. Rămâne problema multiplicităţii în partea stângă a asocierii serves:
De câte aeroporturi e servit un oraş?

Obs. Dacă se consideră că verbul “a servi” se referă la mijlocul de


transport aerian care se găsesşte la cel mult 30 km de un oraş, atunci
multiplicitatea este 0..*, ca în figura de mai jos:
Pasul 3. Modelarea propoziţiilor 8 şi 9

Obs. O escală (stopover) e în conexiune cu zborurile şi aeroporturile, deci


e indicat să se creeze o clasă Stopover:
Obs. O escală se produce într-un şi numai un aeroport şi un aeroport
poate fi folosit pentru mai multe escale.
Întrebare. O escală aparţine unui zbor şi numai unul ?
Răspuns. Nu, există contraexemple date de specialişti. Aşadar o escală
poate aparţine mai multor zboruri.

Pentru a completa diagrama, facem observaţiile:


• asocierea dintre Flight şi Stopover e o agregare, dar nu e compunere;
• escalele sunt ordonate conform cu zborurile
Obs. Clasa Stopover e strâns legată de clasa Airport (multiplicitate 1) şi
nu există ea însăşi, ci ca parte a clasei Flight.

O idee ar fi să considerăm clasa Stopover ca specializare a clasei Airport:

Obs. Nu e soluţia recomandată, din cauza aşa numitei “moşteniri de


implementare”.
Se poate folosi noţiunea de escală (stopover) ca al treilea rol jucat de un
aeroport cu privire la zboruri.

Obs. Clasa Stopover dispare, fiind înlocuită de o clasă de asociere, numită


StopoverInfo.
Pasul 4. Modelarea propoziţiilor 3,4 şi 5

Obs. Trebuie să se facă distincţie între customer şi passenger (exemplu:


un client (customer) poate fi un angajat al celui care călătoreşte)
Obs. Din propoziţia 4, reies multiplicităţile: single flight, single passenger.
Obs. Propoziţia 5 poate fi îndeplinită prin adăugarea a două operaţii în
clasa Booking.
Obs. O soluţie mai simplă se obţine dacă vom considera pasagerul
(passenger) ca atribut în clasa Booking.

Obs. Totuşi, dacă vrem să gestionăm informaţii legate de pasager (cum ar


fi: adresa, numar telefom, e-mail etc) e mai recomandabil să folosim clasa
Passenger, cum am descris anterior.
Revenim la:

Începutul propoziţiei e confuz, deoarece pare că implică direct un customer şi


flight. De aceea, pentru evitarea confuziei, propoziţia poate fi reformulată:

Obs. O rezervare (booking) este făcută de (doar) un customer şi acelaşi


zbor (flight) poate fi afectat de 0 sau mai multe rezervări.
Adăugând şi clasa Passenger, se pune întrebarea:
Câte rezervări poate să aibă un pasager?

Răspuns. La prima vedere, cel puţin una (altfel nu ar fi pasager).


Răspuns complet. E necesar să anticipăm că putem avea 0..*.
Pasul 5. Adăugarea atributelor (attributes), restricţiilor
(constraints) şi calificatorilor (qualifiers)
Reluăm modelul preliminar obţinut până acum:
Pentru fiecare clasă, identificăm principalele atributele (folosind convenţiile
UML):
Completăm modelul cu atribute derivate
Un atribut derivat (vezi Glosar de termeni) este o proprietate, interesantă
pentru analist, dar redundantă ca valoare, pentru că poate fi calculată din alte
elemente existente în model.
Exemplu: durata unui zbor (length), care se obţine ca diferenţă între
arrivalTime şi departureTime, ţinând cont (eventual) şi de arrivalDate şi
departureDate.
Atribute derivate (continuare)

Cum convertim un atribut derivat într-o metodă de design?

Designer-ul are de ales între două metode:


• păstrează un atribut concret în design, care va avea metodele sale de acces
(set şi get); trebuie activat procesul de update ori de câte ori un item din
informaţie, de care depinde atributul, se modifică; - se foloseşte dacă e
necesar ca valoarea atributului derivat să fie prezentă în permanenţă sau dacă
se calculează greu;
• nu stochează valoarea redundantă, dar o calculează la cerere, folosind o
metodă publică; - se foloseşte dacă nu e cerut prea des sau dacă se poate
calcula cu uşurinţă
Adăugarea restricţiilor (constraints) şi calificativilor (qualifiers)

Pentru a schimba un zbor (flight) sau client (customer), rezervarea


respectivă trebuie anulată şi creată una nouă.

Acest fapt se poate realiza folosind restricţia {frozen} pe asocierea potrivită.


(vezi Glosar de termeni)

Pe de altă parte, fiecare zbor e identificat în mod unic printr-un număr.


Putem să convertim atributul number (în clasa Flight) în calificativ (qualifier)
(vezi Glosar de termeni) al asocierii offers dintre clasele AirlineCompany şi
Flight.

Nu trebuie exagerat cu restricţiile. Se recomandă folosirea acelora care sunt


foarte importante, altfel diagrama poate deveni greu de urmărit.
Pasul 6. Folosirea analysis pattern
Clasa Flight are mai multe responsabilităţi:

a) Prima priveşte toate informaţiile ce pot fi găsite în planificarea zborurilor


pentru fiecare companie aeriană: într-adevăr, există un zbor în fiecare luni,
să zicem, între oraşele A şi B, oferit de compania din oraşul A.
b) A doua se referă la informaţiile privind rezervările: cineva nu rezervă un
zbor A-B într-o zi de luni, ci rezervă un zbor A-B în ziua de 09.11.2009 (de
exemplu).
De aceea vom vedea un tip de relaţie de instanţiere dintre clasa
GenericFlight, care are responsabilităţile descrise la punctul a) şi clasa
Flight, care să aibă responsabilităţile de la punctul b).

În plus, să presupunem că o companie anulează nişte zboruri, din oraşul X,


din motive de modernizare a aeroportului, timp de câteva luni. În varianta
iniţială, trebuia să scăpăm de toate instanţele clasei Flight. La sfârşitul
lucrărilor, trebuiau recreate; în varianta a doua pur şi simplu instanţele
pentru zborurile ce pleacă din oraşul X nu vor exista.
Clasa Flight în versiunea iniţială
Separarea responsabilităţilor clasei Flight
Pentru updatarea modelului, trebuie:
• distribuirea atributelor, operaţiilor şi asocierilor clasei Flight între clasele
GenericFlight şi Flight;
• adăugarea unei asocieri “1-*” între clasele GenericFlight şi Flight;

În plus, adăugăm două atribute în clasa GenericFlight care să indice în ce zi


a săptămânii e planificat zborul şi în ce perioadă a anului are loc zborul
(validityPeriod).
E adăugată o restricţie care leagă valorile atributului departureDate din
clasei Flight şi din clasa GenericFlight
Obs. validityPeriod nu e un atribut simplu: putem fi interesaţi de începutul
perioadei, sfârşitul, durata etc. Soluţia ar fi crearea unei clase TimePeriod:

Trebuie adăugată o asociere între Flight şi AirlineCompany.


Distribuirea reponsabilităţilor între clasele GenericFlight şi Flight
Metaclass pattern
Separarea responsabilităţilor poate fi generalizată în forma unui “analysis
pattern”, care poate reutilizat în alte ocazii.

Fie o clasă XX, cu multe responsabilităţi, care nu sunt prezente în fiecare


instanţă.

Adăugăm o clasă TypeXX, distribuim proprietăţile între aceste clase şi le


legăm într-o asociere de tipul “*-1”. TypeXX se numeşte metaclasă,
deoarece conţine informaţii ce descriu clasa XX.
Pasul 7. Structurarea în pachete
Structurarea trebuie să ţină seama de două principii: coerenţa şi
independenţa.
Criteriile de coerenţă presupun a fi îndeplinite:
• obiective: clasele trebuie să returneze servicii de aceeaşi natură către
utilizatori;
• stabilitate: izolăm clasele care sunt stabile de cele care trebuie dezvoltate pe
parcursul proiectului
• durata de viaţă a obiectelor.

Independenţa presupune că divizarea în pachete trebuie făcută astfel încât


să fie minimizate dependenţele dintre pachete.

Propunem divizarea în două pachete:


• primul priveşte definirea zborurilor, foarte stabile (cele din GenericFlight)
• al doilea se refră la rezervări, împreuă cu toate asocierile lor
O soluţie posibilă:
Pasul 8. Generalizarea şi reutilizarea
Se pune problema: putem reutiliza modelul de rezervare bilete pentru o
călătorie cu avionul la o problemă legată de rezervarea biletelor pentru o
călătorie cu autobuzul.
O călătorie cu autobuzul are un oraş de plecare şi un oraş de destinaţie,
respectiv timp şi dată de plecare şi destinaţie. Un client poate rezerva una
sau mai multe călătorii pentru unul sau mai mulţi pasageri.

Modelul va fi foarte asemănător cu modelul călătoriei cu avionul, dar puţin


mai simplu, datorat următoarelor aspecte:
• noţiunea de aeroport nu are echivalent, iar clasa City e direct asociată cu
clasa JourneyByBus;
• distincţia dintre GenericFlight şi Flight nu e transferabilă, deoarece
călătoriile cu autobuzul nu sunt aşa regulate şi nu sunt planificate în avans.
Propunerea unei arhitecturi logice îmbinate
Urmărim obiectivele:
• izolarea claselor care sunt împărţite (shared) într-un nou pachet, pentru a fi
reutilizate
• factorizarea proprietăţilor împărţite într-o clasă abstractă.

Izolarea clasei City


Pe de altă parte, clasele Customer şi Passenger în ambele tipuri de
rezervare. De aceea, e bine să le izolăm într-un nou pachet, dar nu în
acelaşi (Geography), ci separat.

Există asemănare între pachetele FlightBookings şi BusBookings (singura


diferenţă fiind la clasele FlightBooking (redenumită pentru claritate din
Booking) şi BusBooking: au aceleaşi atribute şi aproape aceleaşi asocieri
Se va crea aşadar o supraclasă abstractă Bookings
Soluţia finală va fi următoarea:
Glosar de termeni
Restricţii de schimbare (changeability):
• {frozen}: înseamnă că odată o valoare de atribut sau legătură inserată, nu
poate fi updatată sau ştearsă şi nu pot fi adăugate valori sau legături
atributului, respectiv asocierii;
• {addOnly}: înseamnă că deşi valoarea originală sau legătura originală nu
poate fi updatată sau ştearsă, alte valori sau legături pot fi adăugate atributului
sau asocierii (pentru instanţa obiectului cu restricţii); addOnly are efect doar
dacă multiplicitatea maximă a atributului / rolului asocierii depăşeşte
multiplicitatea minimă.

Asociere calificată (qualifier): este folosită în relaţiile one-to-many şi many-


to-many şi indică modul în care va fi identificat un anumit element al părţii
many a unei asocieri. Un calificativ este un atribut al unei clase de asociere,
care trebuie să reducă multiplicitatea asocierii care a generat clasa de
asociere. Un calificativ este folosit ca un index pentru a găsi obiectele de la
celălalt capăt al unei asocieri şi se reprezintă printr-un dreptunghi mic ataşat
clasei, unde un obiect al clasei, împreună cu valoarea calificativului, reduce
multiplicitatea la cealaltă extremitate a asocierii.

inapoi
Glosar de termeni
Un element derivat, de exemplu atribute sau asocieri, este precedat de slash
”/”. Un atribut derivat nu va fi stocat în obiectele clasei, ci va fi calculat de
fiecare dată. Vezi figura de mai jos

Asocierea derivată mai poate fi reprezentată şi printr-o relaţie de dependenţă,


etichetată cu stereotipul <<derive>>.

inapoi

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