Proiectarea orientată pe obiect din perspectiva ingineriei...

13
1 Universitatea Politehnică București Facultatea de Electronică, Telecomunicații si Tehnologia Informației Proiectarea orientată pe obiect din perspectiva ingineriei software Șabloane de proiectare Student: Luca Adrian Alexandru 441A 2012-2013

Transcript of Proiectarea orientată pe obiect din perspectiva ingineriei...

1

Universitatea Politehnică București Facultatea de Electronică, Telecomunicații si Tehnologia Informației

Proiectarea orientată pe obiect din

perspectiva ingineriei software

Șabloane de proiectare

Student: Luca Adrian – Alexandru

441A

2012-2013

2

Cuprins Șablonul de proiectare COMPOZIT 3 Șablonul de proiectare DECORATOR 4

Șablonul de proiectare OBSERVATOR 6 Șablonul de proiectare STRATEGIE 8

Șablonul de proiectare SINGLETON 10

Șablonul de proiectare PROXY 11

Bibliografie 13

Cuprins

3

Șabloanele de proiectare reprezintă soluții generice la probleme des întâlnite în elaborarea aplicațiilor software. Utilizarea șabloanelor de proiectare este benefica din următoarele motive: . Soluțiile prezentate in cadrul șabloanelor de proiectare au fost analizate de întreaga comunitate a

specialiștilor in programarea orientata-obiect pentru o perioada lunga de timp. Astfel, au fost studiate toate implicațiile utilizării unui anumit șablon, iar soluțiile preconizate au un nivel ridicat de calitate.

. Șabloanele de proiectare reprezintă soluții care trebuie doar adaptate la necesitățile problemei pe care dorim sa o rezolvam. Timpul de dezvoltare al aplicațiilor care folosesc șabloane de proiectare este in general mai redus fata de aplicatiile care sunt dezvoltate pornind de la zero.

Utilizarea șabloanelor de proiectare nu implică numai avantaje, în anumite situații pot apărea, de asemenea, si dezavantaje. De exemplu, pentru anumite aplicații, soluțiile oferite de șabloanele de proiectare pot sa fie mai complexe decât unele concepute special pentru aplicația respectiva. Aceasta complexitate este datorata faptului ca șabloanele de proiectare reprezintă soluții generale care trebuie sa poată fi aplicate la o clasa larga de probleme. De obicei, dezavantajele sunt relativ minore fata de beneficiile aduse de utilizarea șabloanelor de proiectare si pot fi minimizate prin utilizarea diferitelor specializări ale șabloanelor.

Pentru descrierea șabloanelor de proiectare se folosesc diagrame UML însoțite de explicații suplimentare referitoare la aplicabilitatea șablonului, rolul componentelor șablonului, avantajele si dezavantajele utilizării acestuia etc.

Șablonul de proiectare COMPOZIT

Utilizare: este folosit pentru a defini in mod recursiv obiecte complexe prin incorporarea unor obiecte mai simple. Obiectele obținute formează ierarhii parte întreg. O caracteristică esențiala a șablonului de proiectare compozit este aceea ca utilizatorii (clienții) nu trebuie sa facă diferența intre obiectele simple si obiectele complexe, deoarece ambele categorii de obiecte suporta aceleași operații si au aceeași interfața. Obiectele simple si obiectele complexe pot fi utilizate interschimbabil.

Exemplu: in proiectarea unui joc video sunt definite unități simple cum ar fi: arcaș, lăncier, cavaler. Unitățile simple pot fi grupate in formații complexe cum ar fi: careu pentru protejarea unor unități plasate in mijloc, formație dispersata pentru evitarea proiectilelor, așezare in linie, așezare pe 2 anii etc. Formațiile complexe pot fi grupate in continuare pentru a obține structuri si mai complexe cum ar fi careu care protejează o formație organizata pe 2 anii etc.

Proiectanții aplicației isi doresc sa poată trata unitățile complexe intr-o maniera similara unităților primitive, primele beneficiind si de posibilitatea efectuării unor operații suplimentare. Diagrama de clase utilizata este:

4

Fig. 1* Șablonul Compozit poate fi folosit pentru a defini containere, obiecte complexe care includ alte

obiecte mai simple care la rândul lor pot include alte obiecte intr-o maniera recursiva. Obiectele complexe si obiectele primitive partajează aceeași interfața. Din acest motiv, codul-client care folosește aceste obiecte nu trebuie sa facă distincție intre ele. Acest efect este obținut deoarece atât obiectele complexe, cat si obiectele primitive sunt derivate din aceeași c1asa de baza. In plus obiectele complexe se afla intr-o relație de agregare cu aceeași clasa de baza, deoarece un obiect complex poate include alte obiecte componente. Diagrama UML care subliniază aceste relații este:

Fig. 2*

Șablonul de proiectare DECORATOR

Utilizare: adaugă caracteristici si elemente de comportament noi unui obiect in mod dinamic si

transparent, fără a afecta alte obiecte. Poate fi utilizat pentru situații in care anumite responsabilitati ale obiectului pot fi acordate/ retrase. Reprezintă o alternativa la utilizarea subclaselor, mai ales atunci când folosirea acestora ar determina crearea unei structuri arborescente de clase si subclase foarte stufoasa.

5

In esența, șablonul Decorator reprezintă o soluție atunci când ne dorim sa cream un obiect, sa modificam comportamentul metodelor obiectului după ce l-am creat, sa revenim la vechiul comportament, totul fără a afecta codul client care interacționează cu obiectul.

Exemplu: consideram un joc de tip Tamagochi in care mica creatura ce trebuie îngrijita adora produsele furnizate de o cofetărie. Prăjiturile in cadrul acestui joc sunt caracterizate de mai multe atribute comune printre care ingrediente, dimensiunea minima a platoului pe care pot fi prezentate, greutatea si numărul de calorii. Exisa numeroase subtipuri de prăjituri cum ar fi Tort diplomat, Negresa, Tarta cu fructe, Cremșnit, Savarina, fiecare din aceste subtipuri având elemente specifice proprii. Îngrijitorul poate decide sa adauge la o prăjitura, in momentul in care o cumpăra, diverse topinguri cum ar fi frișca, salata de fructe sau bomboane colorate. Un toping adăugat la o prăjitura schimba caracteristicile acesteia. Micul Tamagochi poate renunța la toping in momentul in care primește o prăjitura, consumând-o numai pe aceasta din urma. Caracteristicile alimentelor mâncate de micul Tamagochi ii modifica acestuia starea de sănătate si dorința de joaca.

Elementele determinante pentru utilizarea șablonului Decorator, prezente in descrierea acestui exemplu, sunt: O prăjitura particulara (un obiect din clasa Prăjitura) este caracterizata la momentul in care a fost

creata de un set de atribute incluzând asta ingredientelor, dimensiunea, greutatea, numărul de calorii. Caracteristicile unei prăjituri particulare se pot modifica pe durata existentei acesteia prin adăugarea

sau eliminarea unor toping-uri.

Exisa mult prea multe combinații tip prajitură-toping, pentru a defini cate o subclasa pentru fiecare pereche in parte. Mai mult, topingurile adăugându-se si eliminându-se dinamic pe durata existentei

unei prăjituri, utilizarea unor subclase de tipul Savarina cu Bomboane colorate nu este utila deoarece

un obiect, odată construit, nu își poate schimba clasa căreia ii aparține. Soluția de proiectare aleasa

împacă existenta a doua clase de baza: Prăjitura si Toping. Pornind de la clasa Prăjitura se deriveaza

diferite subcategorii cum ar fi TortDiplomat, Negresa etc. Asemănător, din clasa Toping deriva

diferite tipuri de toping cum ar fi TopingFrisca, TopingFructe sau TopingBomboane. Un obiect din

clasa Toping include ca data membru un pointer (referința) către un obiect din clasa Prăjitura căruia

ii schimba caracteristicile.

Structura soluției este descrisa de următoarea diagrama UML:

Fig. 3*

6

Relativ la aceasta diagrama de clase avem următoarele observații: Fiecare obiect din clasa Toping conține un pointer (referința) către obiectul din clasa

Prăjitura ale cărui caracteristici sunt modificate (se observa in diagrama legătura de agregare intre clasa Toping si clasa Prăjitura). Acest obiect Prăjitura este specificat in cadrul constructorului clasei Toping. Practic, un obiect din clasa Toping încapsulează un obiect din clasa Prăjitura, modificând modul in care acesta din urma se prezintă către exterior. Obiectele de tipul celor din clasa Toping poarta numele de decoratori.

Obiectele Prăjitura au o existența independenta de eventualele obiecte Toping ce le decorează (in diagrama avem o relație de agregare si nu una de compoziție).

Clasa Prăjitura conține numai metode virtuale. Aceste metode pot fi redefinite in cadrul tipurilor particulare de prăjituri: Savarina, Negresa, TortDiplomat.

Clasa Toping moștenește clasa Prăjitură. Interfața clasei Toping include interfața clasei Prăjitura. Este natural ca prăjiturile cu toping sa se comporte similar unor prăjituri obtinute având unele caracteristici si elemente de comportament suplimentare. In general, o operație din interfața clasei Toping va apela operația corespunzătoare din cadru clasei Prăjitura efectuând eventual pre-procesări si post-procesări suplimentare.

Șablonul Decorator ne permite sa adăugam sau sa retragem in mod dinamic proprietățile unui

obiect fără a afecta alte obiecte din aceeași categorie. Pentru a realiza acest lucru:

Obiectul decorator conține o referința/pointer către obiectul al cărui comportament este modificat.

Obiectul decorator si obiectul al cărui comportament este modificat sunt derivate din aceeași clasa. In acest mod, obiectul decorator poate înlocui obiectul decorat in mod transparent pentru client (clientul nu cunoaște daca lucrează cu decoratorul sau direct cu obiectul de baza).

A1ternativ, c1asa Decorator poate fi derivata direct din clasa Decorat.

Diagrama UML generica pentru șablonul de proiectare Decorator este:

Fig. 4*

Șablonul de proiectare OBSERVATOR

Utilizare: este folosit atunci când unul sau mai multe obiecte numite observatori sunt interesate

sa monitorizeze starea unui obiect numit observabil. Situația poate fi reprezentata cu ajutorul unei dependente unul la mai mulți intre obiectul observabil ai obiectele observator. Esența dependentei este aceea ca atunci când observabilul isi schimba starea, toate dependentele lui (toți observatorii asociați) sunt anunțate si eventual actualizate. Separarea si încapsularea observabilului si observatorilor permite reutilizarea si modificarea acestora in mod independent. Putem spune ca observabilul si observatorii sunt slab cuplați. Prin cuplare slaba intre doua clase înțelegem ca intre acestea exista relativ puține interdependente, iar interacțiunile au loc prin intermediul unor interfețe bine definite. Clasele slab cuplate de obicei pot fi reutilizate independent una de cealaltă.

7

Exemplu: consideram situația unui diplomat de la ambasada care trebuie sa anunțe serviciul de protecție cu privire la deplasările pe care le efectuează. Diplomatul va reprezenta obiectul observabil, iar agenții serviciului de paza vor fi obiectele observator.

Diagrama UML care schematizează aceasta situație este:

Fig. 5*

Diagrama pune în evidenţă câteva caracteristici esenţiale pentru structura şablonului de proiectare Observator:

Obiectele observabile menţin informaţii despre starea în care se află. În exemplul nostru particular,

informaţiile de stare sunt reprezentate de data membru _inDeplasare din cadrul clasei Diplomat, care este un

subtip de Observabil.

Obiectele observabile menţin o evidenţă a obiectelor observator care le monitorizează. În momentul în care

starea unui obiect observabil se modifică, acesta va notifica toţi observatorii pe care îi are în evidenţă despre

schimbare. De obicei, evidenţa obiectelor observator este realizată prin menţinerea de referinţei pointeri către

aceştia într-o structură de date dedicată cum ar fi o listă de observatori.

În momentul în care un obiect observator este anunţat de schimbarea stării unui obiect observabil, îi poate

adresa acestuia din urmă interogări suplimentare pentru a determina natura exactă a modificării. Diagrama de

interacţiune în cazul exemplului nostru este:

Fig. 6*

8

Şablonul de proiectare Observator se utilizează atunci când un obiect numit observator trebuie să

monitorizeze schimbările În starea unui alt obiect numit observabil. Obiectul observabil menţine o

evidenţă a obiectelor Observator care îl monitorizează. In momentul apariţiei unei modificări,

observabilul va notifica toţi observatorii aflaţi in evidenţa lui.

Interfaţa unui obiect observabil generic conţine operaţii pentru adăugarea/ştergerea de observatori şi pentru notificarea tuturor observatorilor aflaţi in evidenta.

Elementele care compun starea unui observator diferit de la un tip particular de observația altul. Din acest motiv, informaţiile de stare sunt plasate de obicei in cadrul subclaselor tipului Observabil.

Diferitele subtipuri de observatori pot reacţiona diferit la apariţia unor schimbări de stare,

diferenţele fiind evidenţiate in cadrul subclaselor lui Observator.

Structura generală a şablonului de proiectare Observator este prezentată de diagrama de clase UML:

Fig. 7*

Șablonul de proiectare STRATEGIE

Utilizare: defineşte o familie de algoritmi, încapsulaţi individual şi interschimbabili. Ideea fundamentală este de a obţine o cuplare slabă între algoritm şi datele care trebuie procesate de către acesta, date aflate în posesia clientului care utilizează algoritmul. O astfel de cuplare permite clientului să schimbe algoritmul folosit pentru procesare cu un efort minim în cazul în care are la dispoziţie mai mulţi algoritmi care pot realiza operaţiile dorite peste setul de date disponibil la client.

Exemplu: considerăm o aplicaţie care selectează melodiile care vor fi difuzate de către un DJ. DJ-ul organizează seri cu tematici diferite, muzică clasică, rock, trance etc. Pentru fiecare tematică trebuie utilizat un algoritm special pentru a selecta melodiile din lista tuturor melodiilor aflate la dispoziţia lui.

Pentru a putea comuta uşor de la o metodă de selecţie la alta vom separa algoritmii de selecţie în clase dedica te, separate de clasa DI. Aceasta din urmă conţine lista tuturor melodiilor şi un pointer către clasa care reprezintă metoda de selecţie utilizată la momentul curent. Pentru ca metodele de selecţie să fie interschimbabile, clasele care le conţin vor fi derivate din aceeaşi clasă de bază, fapt care va asigura o interfaţă comună.

9

Diagrama UML de clase a aplicaţiei exemplu include relaţiile:

Fig. 8*

Există o clasă interfaţă care descrie intrările şi ieşirile algoritmilor. Algoritmii au o interfaţă comună

(intrări si ieşiri similare) pentru a putea fi utilizaţi în mod interschimbabil. În diagramă, clasa care

descrie necesităţile de I/0 ale algoritmilor este clasa Muzica. Metoda Interpret va furniza ca ieşire

titlul melodiei selectate.

Modul în care se calculează ieşirile în funcţie de intrări diferă de la un algoritm la altul (de la o

strategie la alta). Aceste diferenţe sunt reprezentate de mai multe clase derivate din clasa interfaţă,

fiecare reprezentând o anumită strategie, un anumit comportament. În cadrul diagramei apar

mai multe metode strategii) de selecţie diferite a melodiilor, reprezentate de clasele derivate Rock,

Clasica, Trance.

Strategiile sunt utilizate de clase client cum este DJ în exemplul nostru. Clasele-client utilizează

diferite metode pentru a accesa o strategie în vederea utilizării, este comun ca o astfel de clasă să

conţină un pointer sau o referinţă către strategia care se utilizează la momentul curent. În diagramă,

apare pointer-ul _pMuzicaAleasa. În aceste condiţii, între clasa DJ şi clasa Muzica apare o relaţie de agregare, clasa DJ include un pointer către un obiect din clasa Muzica, acesta din urmă

reprezentând o strategie particulară de alegere a melodiilor. Acelaşi obiect din clasa Muzica poate fi

referit simultan de mai multe obiecte DJ.

In proiectarea şablonului Strategy se au În vedere următoarele considerente:

Fiecare strategie distinctă va fi Încapsulată În cadrul unei clase. În multe cazuri aceste

clase nu au date-membru reprezentând doar secvenţe de prelucrări.

Clasele reprezentând strategii sunt derivate dintr-o aceeaşi clasă de bază comună. Astfel,

ele au aceeaşi interfaţă şi sunt uşor interschimbabile.

Specificatorii de acces sunt importanţi pentru elaborarea unor interfeţe bine definite, necesare

pentru reutilizarea codului.

10

Fig. 9*

Șablonul de proiectare SINGLETON

Utilizare: ne asigură că o clasă are o singură instanţă, furnizând un punct global de acces la ea. Se poate

folosi atunci când o clasă are nevoie de o instanţă unică, iar celelalte clase trebuie să acceseze instanţa

dintr-un singur punct binecunoscut. Clasele de acest tip poartă numele de clase Singleton.

Stabilirea numărului de instanţe (obiecte) dintr-o anumită clasă poate fi lăsată la latitudinea clienţilor

care utilizează clasa respectivă, aceştia construind atâtea obiecte câte le sunt necesare. În anumite

cazuri însă, proiectanţii unei clase doresc să impună clienţilor restricţii asupra numărului de obiecte din

această clasă care pot fi create. Exemplu: în cadrul unui simula tor pentru pescuit, proiectanţii unei clase Undi ta doresc să se

asigure că la un moment dat există numai o singură instanţă a acestei clase. În acest sens ei pot opta pentru două variante de proiectare.

Toate datele membru şi toate metodele clasei Undita sunt declarate static. Elementele statice ale unei clase sunt specifice întregii clase şi nu unei instanţe particulare a acesteia. Ca urmare, obiectele dintr-o astfel de clasă nu au o stare proprie (nu au valori proprii diferite pentru datele membru ale clasei), ele partajează aceleaşi date membru comune.

Diagrama UML corespunzătoare este:

Fig. 10*

11

Observaţii

1. Într-o diagramă de clase UML, toţi membrii stației ai unei clase sunt subliniaţi. 2. Clasa nu are constructor deoarece nu există date membru specifice instanţelor care să trebuiască

să fie iniţializate la crearea unui obiect particular. Toate datele membru sunt declarate static şi sunt comune tuturor instanţelor. Ele vor fi iniţializate înainte de începerea execuţiei programului cu valorile specifica te la definirea lor.

Şablonul Singleton este folosit pentru a defini clase care au o singură instanţă.

Instanţa unică este global accesibilă, poate fi accesată din orice punct al programului. Accesibilitatea globală este asigurată prin intermediul specificatorului static. Metodele declarate

static pot fi apelate din orice punct al programului folosind numele clasei. Constructorii clasei şi operatorii de atribuire sunt declaraţi private sau protected. În acest mod

codul-client nu poate construi noi instanţe ale clasei.

Șablonul de proiectare PROXY

Utilizare: furnizează un înlocuitor (surogat) pentru un alt obiect pentru a realiza controlul

accesului la acesta din urmă. Obiectul Proxy acţionează ca un intermediar între codul-client şi obiectul

care furnizează serviciile cerute de client. Principalul model de interacţiune specific şablonului Proxy

este reprezentat grafic în următoarea diagramă care subliniază rolul de intermediar al obiectului Proxy între entitatea-client şi obiectul furnizor de servicii.

Fig. 11*

Acest şablon este întotdeauna util atunci când se doreşte un apel al unui obiect într-un mod mai

sofisticat decât printr-un simplu pointer. De exemplu, putem dori o contorizare a cererilor adresate unui

obiect şi această contorizare poate fi realizată la nivelul obiectului proxy. în acest caz obiectul proxy

acţionează ca un pointer sau o referinţă cu posibilităţi suplimenta re (înlocuitor pentru un pointer sau o

referinţă obişnuită), de unde şi numele de smart reference sau smart pointer (pointer inteligent). Sau

dorim o filtrare şi o prioritizare a cererilor in funcţie de drepturile de access ale obiectelor-client.

Obiectele proxy de acest tip poartă numele de Protection proxy, ele controlând accesul la obiectul

12

original. Sau în cazul în care obiectul server primeşte cereri care sunt solicitante din punct de vedere

computaţional, obiectul proxy poate furniza răspunsuri intermediare până la primirea celui final.

Remote proxy realizează o reprezentare locală pentru un obiect dintr-un spaţiu de adresă diferit, fiind

util atunci când două aplicaţii trebuie să colaboreze, obiectele uneia apelând la serviciile oferite de

obiectele celei de-a doua aplicaţii.

Exemplu: luăm în considerare un joc care presupune construirea de clădiri incluzând. şi case de

locuit. Simularea construcţiei unei clădiri este o operaţie consumatoare de timp. Ca atare dorim ca pe

perioada unei operaţii de construire, solicitantul construcţiei să primească un mesaj prin care să fie

anunţat că activitatea cerută este in derulare şi va trebui să aştepte. Responsabilitatea generării

mesajului de aşteptare poate fi trecută în sarcina unui obiect Proxy care în acelaşi timp poate genera în

cadrul jocului şi o imagine cu o clădire în construcţie.

Pentru acest exemplu, obiectul proxy va trebui să accepte aceleaşi cereri ca şi obiectul pe care îl

substituie. Drept urmare, atât clasa Proxy cât şi clasa furnizoare de servicii de construire vor fi derivate din aceeaşi clasă de bază pentru a avea aceeaşi interfaţă. în alte situaţii, interfaţa obiectului proxy va fi

diferită de cea a clasei furnizoare de servicii, obiectul proxy realizând astfel o compatibilizare între

client şi furnizorul de servicii.

Clasă de bază numită ConstructorCladiri care va avea doar funcţii virtuale deoarece ea reprezintă interfaţa comună a claselor specializate pentru construcţia diferitelor clădiri şi a clasei Proxy. Clasa

ConstructorCasa reprezintă un constructor particular

specializat în construirea de case. Clasa Joc reprezintă codul-client

(un joc particular) care solicită construirea de clădiri în timpul execuţiei aplicaţiei, în cazul exemplului nostru, atunci când populaţia depăşeşte un anumit număr.

Diagrama UML corespunzătoare exemplului prezentat este următoarea:

Fig. 12*

13

Bibliografie

1. Ian Sommerville - Software Engineering

2. Grady Broch – Object Oriented Development

3. Zhiming Liu - Object-Oriented Software Development with UML

4. http://web.info.uvt.ro/~oaritoni/inginerie/index/curs.html

5. http://users.cs.tuiasi.ro/~fleon/curs_ip.htm

* diagrame UML generate cu MathWork