29.04.2013 Views

Tehnici de proiectare software - Tipografia

Tehnici de proiectare software - Tipografia

Tehnici de proiectare software - Tipografia

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

TEHNICI DE PROIECTARE SOFTWARE<br />

Proiectare orientată pe şabloane<br />

Prof. univ. Dr. Tudor Bălănescu


Cuprins<br />

I. Introducere...........................................................................................1<br />

1.1. De ce şabloane?............................................................................................ 1<br />

1.2. Scurt istoric ................................................................................................. 1<br />

1.3. Concepte <strong>de</strong> bază în şabloane..................................................................... 2<br />

II. Şabloane creaŃionale ..........................................................................3<br />

II. 1. Abstract Factory........................................................................................3<br />

11.2. Buil<strong>de</strong>r............."...........................................................................................7<br />

11.3. Factory Mcthod ........................................................................................11<br />

11.4. Prototype...................................................................................................14<br />

11.5. Singleton................................................................................................... 17<br />

III. Şabloane comportamentale ............................................................ 20<br />

111.1. Chain Of Responsibility..........................................................................20<br />

111.2. Command ............................................................................................... 24<br />

111.3. Interpreter ...............................................................................................28<br />

111.4. Iterator....................................................................................................31<br />

111.5. Mediator ................................................................................................. 35<br />

111.6. Memento ................................................................................................. 38<br />

111.7. State ........................................................................................................ 41<br />

111.8. Strategy...................................................................................................45<br />

111.9. Visitor ..................................................................................................... 49<br />

111.10. Template Method ................................................................................. 54<br />

IV. Şabloane structurale ....................................................................... 58<br />

IV.l. Adapter ................................................................................................... 58<br />

IV.2. Bridge.......................................................................................................62<br />

IV.3. Composite ................................................................................................65<br />

IV.4. Decorator .................................................................................................69<br />

IV.5. Faca<strong>de</strong> ..................................................................................................... 73<br />

IV.6. Flyvveight ................................................................................................ 76<br />

IV.7. Half-Objcct Plus Protocol (HOPP)........................................................ 79<br />

IV.8. Proxy ........................................................................................................83<br />

V. Concluzii .........................................................................................87<br />

Bibliografie ............................................................................................88


I. Introducere<br />

1.1. De ce şabloane?<br />

De multe ori realizarea unui proiect <strong>software</strong>, asemănător construcŃiei unei<br />

^ase. nu conduce la rezultatul scontat. De aceea avem nevoie <strong>de</strong> îndrumare, <strong>de</strong><br />

echivalentul unui arhitect, <strong>de</strong> cineva care posedă cunoştinŃele şi experienŃa necesare<br />

pentru <strong>de</strong>sign-ul unui <strong>software</strong>: avem nevoie <strong>de</strong> un guru în domeniul proiectării.<br />

Din păcate, astfel <strong>de</strong> guru nu sunt prea mulŃi în lume, prin urmare companiile<br />

trebuie să-şi formeze proprii experŃi <strong>software</strong>. Deci dorim crearea unui <strong>software</strong> <strong>de</strong><br />

calitate, dar nu ştim cum să luăm <strong>de</strong>ciziile corecte, <strong>de</strong>cizii care să ne conducă în final<br />

'a realizarea unui produs <strong>de</strong> calitate.<br />

Dacă totuşi există o modalitate <strong>de</strong> a colecŃiona cunoştinŃele <strong>de</strong> care avem<br />

r.evoie tară prea mari dificultăŃi? Dacă putem totuşi să înregistrăm conceptele <strong>de</strong><br />

.iesign <strong>de</strong> <strong>software</strong>, construind o bază pentru generaŃiile viitoare? Există o astfel <strong>de</strong><br />

cale - şabloanele <strong>de</strong> <strong>proiectare</strong>.<br />

Se ştie că experŃii recurg <strong>de</strong>seori la aplicarea unor soluŃii pe care le-au mai<br />

rolosit atunci când rezolvă probleme noi. Apelează la vechile soluŃii pe care le<br />

generalizează, adaptând apoi soluŃia generală Ia contextul noii probleme.<br />

I<strong>de</strong>ea din spatele şabloanele <strong>de</strong> <strong>proiectare</strong> este realizarea unei căi standard <strong>de</strong><br />

reprezentare a soluŃiilor generale ale problemelor <strong>de</strong>s întâlnite în <strong>de</strong>zvoltarea <strong>de</strong> -<br />

oftware. Există câteva avantaje ale acestui lucru:<br />

- cu timpul se pot construi cataloage <strong>de</strong> şabloane<br />

- începătorii în <strong>de</strong>zvoltarea <strong>de</strong> <strong>software</strong> pot beneficia <strong>de</strong> pe urma<br />

experienŃei acumulate în trecut<br />

- şabloanele standard îi ajuta atât pe începători cât şi pe experŃi să înŃeleagă<br />

implicaŃiile <strong>de</strong>ciziilor pe care le iau<br />

- şabloanele <strong>de</strong> <strong>proiectare</strong> au un vocabular comun, acest lucru făcând<br />

comunicarea <strong>de</strong>ciziilor către cei care <strong>de</strong>zvolta <strong>software</strong>-ul mult mai uşoară; <strong>de</strong>cât să<br />

r.escriem un <strong>de</strong>sign în <strong>de</strong>taliu, putem folosi un nume <strong>de</strong> şablon pentru a explica ceea<br />

.e dorim să realizăm; putem <strong>de</strong> asemenea face o legătură între şabloane, putându-se<br />

.-.cutând <strong>de</strong>spre un set <strong>de</strong> şabloane <strong>de</strong> <strong>proiectare</strong> pentru Smalltalk într-o prezentare la<br />

. nferinŃa OOPSLA din 1987. James Coplien a promovat <strong>de</strong> asemenea şabloanele,<br />

^r;md o carte <strong>de</strong>spre <strong>de</strong>zvoltarea şabloanelor pentru C++ la începutul anilor '90.<br />

OOPSLA a oferit mediul excelent pentru schimbul <strong>de</strong> i<strong>de</strong>i între creatorii<br />

^Hoanelor <strong>de</strong> <strong>proiectare</strong>. Un alt forum important care a ajutat la evoluŃia şabloanelor<br />

.: rost Hillsi<strong>de</strong> Group, creat <strong>de</strong> Kent Beck şi Grady Booch.


Probabil contribuŃia cea mai importantă în popularizarea şabloanelor <strong>de</strong><br />

<strong>proiectare</strong> a avut-o cartea din 1995 "Şabloane <strong>de</strong> <strong>proiectare</strong>: Elemente <strong>de</strong> re utilizare a<br />

<strong>software</strong>-ului orientat pe obiecte", scrisa <strong>de</strong> Erich Gamma, Richard Helm, Ralph<br />

Johnson şi John Vlissi<strong>de</strong>s.<br />

După publicarea acestor două cărŃi, şabloanele <strong>de</strong> <strong>proiectare</strong> au început să se<br />

bucure <strong>de</strong> un mare interes în rândul comunităŃii <strong>software</strong>. Limbajul Java s-a <strong>de</strong>zvoltat<br />

in acelaşi timp în care şabloanele câştigau popularitate, <strong>de</strong>ci cei care foloseau Java au<br />

început să aplice şabloanele în proiectele lor. Continua creştere a popularităŃii<br />

şabloanele <strong>de</strong> <strong>proiectare</strong> în Java s-a manifestat prin prezentări în conferinŃe ca<br />

JavaOne. precum şi prin articole privind şabloanele în revistele <strong>de</strong>dicate limbajului<br />

Java.<br />

1.3. Concepte <strong>de</strong> baza în şabloane<br />

La baza i<strong>de</strong>ii <strong>de</strong> şablon stă conceptul <strong>de</strong> standardizare a informaŃiilor <strong>de</strong>spre o<br />

problemă comună şi soluŃia ei. Unul din cele mai folositoare rezultate ale muncii lui<br />

Alexan<strong>de</strong>r a fost <strong>de</strong>zvoltarea formei sau formatului în care e reprezentat şablonul.<br />

Este important ca un şablon să aibă un nume sugestiv şi să răspundă la<br />

întrebarea "Ce face aceste şablon?". în plus, trebuie să mai includă o discuŃie asupra<br />

problemei, o explicaŃie asupra modului în care şablonul rezolvă problema şi o<br />

indicaŃie privind beneficiile şi importanŃa folosirii şablonului respectiv.<br />

Evi<strong>de</strong>nt, <strong>de</strong>-a lungul timpului au apărut variaŃii ale formei Alexandriene,<br />

<strong>de</strong>zvoltate conform necesităŃiilor apărute în crearea unui anumit <strong>software</strong>. în cele ce<br />

urmează se va folosi forma formată din următoarele template-uri:<br />

a) Nume - un nume <strong>de</strong>scriptiv al şablonului<br />

b) Cunoscut şi ca - un nume alternativ, dacă există<br />

c) ProprietăŃile şablonului - clasificarea şablonului. Şablonul va fi <strong>de</strong>finit prin:<br />

obiecte<br />

l.Tip:<br />

- creationale - şabloane pentru crearea obiectelor<br />

- comportamentale - şabloane ce coordonează interacŃiunea obiectelor<br />

- structurale - şabloane care asigură relaŃiile statice şi structurale dintre<br />

- <strong>de</strong> sistem - şabloane care asigură interacŃiune la nivel a sistemului<br />

2. Nivel:<br />

- clasă - şablonul aplicat unei singure clase<br />

- componentă - şablonul ce cuprin<strong>de</strong> un grup <strong>de</strong> clase<br />

- arhitectural - şablonul e folosit pentru a coordona acŃiunile sistemului<br />

sau ale subsistemului<br />

d) Scop - o scurtă explicaŃie privind ceea ce face şablonul<br />

e) Introducere - o scurtă <strong>de</strong>scriere a unei probleme un<strong>de</strong> poate fi folosit şablonul<br />

f) Utilizare - un<strong>de</strong> şi cum se poate folosi şablonul <strong>de</strong> <strong>proiectare</strong><br />

L T ) Descriere - discuŃie <strong>de</strong>taliată asupra şablonului - ce face şi cum se comportă<br />

h) Implementare - o discuŃie <strong>de</strong>spre ce trebuie făcut pentru a implementa şablonul<br />

î) Beneficii şi inconveniente - consecinŃele utilizării şablonului<br />

I) Variante ale şablonului - implementări alternative posibile<br />

k) Şabloane asociate - alte şabloane care sunt asociate sau apropiate <strong>de</strong> şablon


II. Şabloane creaŃionale<br />

Aceste şabloane realizează unul dintre cele mai comune lucruri în programarea<br />

iernată pe obiecte - crearea obiectelor într-un sistem. Majoritatea sistemelor<br />

ientate pe obiecte necesită instanŃierea în timp a multor obiecte, iar aceste şabloane<br />

: iiină crearea obiectelor prin:<br />

- instanŃiere generică - aceasta face ca obiectele să fie create în sistem fără a<br />

:ntifica o clasă specifică în cod<br />

- simplitate - unele şabloane fac uşoara crearea unui obiect, astfel că nu mai<br />

■nuie scris un cod mare şi complex pentru instanŃierea obiectului<br />

- constructori - unele şabloane forŃează constructorii <strong>de</strong> un anumit tip pentru a<br />

:a obiectele în cadrul sistemului<br />

II.l. Abstract Factory<br />

• Cunoscut şi ca Kit sau Toolkit<br />

ProprietăŃi<br />

■ Scop<br />

- Tip: creaŃional<br />

- Nivel: componentă<br />

Să asigure o modalitate <strong>de</strong> creare a familiilor <strong>de</strong> obiecte <strong>de</strong>pen<strong>de</strong>nte sau<br />

■r.rudite fără a specifica clasele lor concrete.<br />

• Introducere<br />

Presupunem că <strong>de</strong> doreşte crearea unei aplicaŃii care să fie un manager<br />

personal <strong>de</strong> informaŃii, cuprizând adrese şi numere <strong>de</strong> telefoane. AplicaŃia va fi o<br />

combinaŃie între o carte <strong>de</strong> telefoane şi un planificator personal, urmând a utiliza<br />

intensiv datele ce conŃin adresele şi numerele <strong>de</strong> telefoane. Se pot crea iniŃial clase -<br />

are să reprezinte adresa şi numărul <strong>de</strong> telefon. Se scrie apoi codul acestor clase astfel<br />

încât ele să reŃină informaŃiile relevante. De exemplu, toate numerele <strong>de</strong> telefon din<br />

America <strong>de</strong> Nord sunt formate din maxim zece cifre iar codul poştal are un format<br />

specific.<br />

Imediat ce codul claselor a fost scris corespunzător acestor condiŃii, ne dăm<br />

seama că trebuie să facem acelaşi lucru şi pentru adrese şi numere <strong>de</strong> telefon din altă<br />

;ară. <strong>de</strong> exemplu Olanda. Dar aici sunt alte reguli privind numerele <strong>de</strong> telefon şi<br />

adresele, prin urmare clasele Address şi PhoneNumber trebuie modificate pentru a lua<br />

in consi<strong>de</strong>rare regulile din noua Ńară.


Urmează apoi introducerea informaŃiilor <strong>de</strong>spre altă Ńară şi aşa mai <strong>de</strong>parte. Cu<br />

fiecare nou set <strong>de</strong> reguli, clasele Address şi PhoncNumber <strong>de</strong>vine din ce în ce mai<br />

încărcate cu cod şi mai greu <strong>de</strong> lucrat cu ele. necesitând mereu şi o noua compilare.<br />

Şablonul Abstract Factory rezolvă această problemă. Folosind acest şablon, se<br />

poate <strong>de</strong>fini o clasă generică AddressFactory care produce obiecte ce urmează<br />

şablonul general dat <strong>de</strong> Address şi PhoneNumber.<br />

Astfel fiecare Ńară va avea propria versiune a claselor Address şi<br />

PhoneNumber. In loc <strong>de</strong> a adaugă mereu informaŃie claselor, se extin<strong>de</strong> Address la<br />

AddressHolland şi PhoneNumber la PhoneNumberHolland. InstanŃe ale ambelor clase<br />

sunt create printr-o clasa AddressFactoryOlanda. Acest lucru oferă o mare libertate <strong>de</strong><br />

extin<strong>de</strong>re a codului iară a face modificări structurale majore în restul sistemului.<br />

• Utilizare<br />

Şablonul Abstract Factory se foloseşte când:<br />

- clientul e in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> crearea produselor<br />

- aplicaŃia e configurată folosind una din multele familii <strong>de</strong> produse<br />

- obiectele trebuie create ca un set pentru a fi compatibile<br />

- se doreşte relevarea unei colecŃii <strong>de</strong> clase doar prin legăturile şi relaŃiile<br />

dintre clase şi nu prin implementarea lor<br />

■ Descriere<br />

Câteodată o aplicaŃie necesită folosirea unei game diferite <strong>de</strong> resurse sau medii<br />

operative. Exemple ar fi lucrul în Windows, fişierele sistem sau comunicarea cu alte<br />

aplicaŃii sau sisteme.<br />

Astfel că se doreşte realizarea unei aplicaŃii <strong>de</strong>stul <strong>de</strong> flexibile încât să<br />

folosească o gama larga <strong>de</strong> resurse fără a fi nevoie să se rescrie aplicaŃia <strong>de</strong> fiecare<br />

dată când o nouă resursă e introdusă. O modalitate <strong>de</strong> a rezolva această problemă este<br />

<strong>de</strong> a introduce un creator generic <strong>de</strong> resurse şi anume Abstract Factory. Acesta are una<br />

sau mai multe meto<strong>de</strong> <strong>de</strong> creare, care pot fî apelate pentru a produce resurse generice<br />

sau produse abstracte.<br />

Tehnologia Java rulează pe mai multe platforme, <strong>de</strong> fiecare dată existând o<br />

altă implementare a fişierelor sistem. SoluŃia pe care Java a adoptat-o este <strong>de</strong> a<br />

abstractiza conceptele <strong>de</strong> fişiere şi <strong>de</strong> a nu arată implementarea lor propriu-zisă.<br />

AplicaŃia poate fi <strong>de</strong>zvoltată folosind capacităŃile generice ale resurselor care prezintă<br />

o funcŃionalitate reală.<br />

în timpul rulării, clasele ConcreteFactories şi ConcreteProducts sunt create şi<br />

folosite <strong>de</strong> aplicaŃie. Clasele concrete sunt conforme cu <strong>de</strong>finirile lor din clasele<br />

AbstractFactory şi AbstractProducts, astfel că ele pot fi utilizate direct fără a fi<br />

rescrise sau recompilate.


Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Abstract Factory este următoarea:<br />

De regulă pentru implementarea şablonului Abstract Factory <strong>de</strong> folosesc:<br />

- AbstractFactory - o clasă abstractă sau o interfaŃă care <strong>de</strong>fineşte meto<strong>de</strong>le <strong>de</strong><br />

. _/.:e ale produselor abstracte<br />

- AbstractProduct - o clasă abstractă sau o interfaŃă care <strong>de</strong>scrie<br />

- ".vM-iamentul general al resurselor care vor 1! folosite <strong>de</strong> aplicaŃie<br />

- ConcreteFactory - o clasă <strong>de</strong>rivată din clasa AbstractFactory şi care<br />

■ .mentează meto<strong>de</strong> <strong>de</strong> creare pentru unul sau mai multe produse concrete<br />

- ConcreteProduct - o clasă <strong>de</strong>rivată din clasa AbstractProduct şi care conŃine<br />

■ j:nentarea unei resurse sau a unui mediu <strong>de</strong> operare specific<br />

5


Beneficii şi inconveniente<br />

In şablon Abstract Factory ajută la creşterea pe ansamblu a flexibilităŃii unei<br />

i caŃii. Această flexibilitate se manifestă atât în etapa <strong>de</strong> <strong>de</strong>sign cât şi în cea <strong>de</strong><br />

.;ve a aplicaŃiei. în timpul <strong>de</strong>sign-ului. trebuie să se <strong>de</strong>cidă viitoarele utilizări ale<br />

:caŃiei. La rulare, aplicaŃiei îi pot fi uşor integrate noi caracteristici şi resurse.<br />

Un alt beneficiu al acestui şablon este acela că el poate simplifica testarea<br />

:ului aplicaŃiei. Implementarea unor clase <strong>de</strong> test şi anume TestConcreteFactory şi -<br />

tConcretcProduct este simplă, putându-se astfel simula comportamentul aşteptat al<br />

.:rselor.<br />

Pentru a putea beneficia <strong>de</strong> acest şablon, trebuie <strong>de</strong>finită cu atenŃie o interfaŃă<br />

.crică corespunzătoare pentru produsul abstract. Daca produsul abstract e <strong>de</strong>finit -<br />

rect. realizarea unor produse concrete poate fi dificilă sau chiar imposibilă.<br />

Variante ale şablonului<br />

După cum s-a menŃionat anterior, se pot <strong>de</strong>fini AbstractFactory şi<br />

stractProduct ca interfeŃe sau clase abstracte, în funcŃie <strong>de</strong> necesităŃile aplicaŃiei sau<br />

^referinŃe. Unele variante ale şablonului Abstract Factory permit producerea mai<br />

.'.tor obiecte ConcreteFactory. rezultând o aplicaŃie care poate folosi simultan<br />

tiiii multiple <strong>de</strong> ConcreteProducts.<br />

Şabloane asociate<br />

Printre şabloanele asociate lui Abstract Factory se numără:<br />

- Factory Method<br />

- Singleton<br />

- Data Access Object<br />

Exemplu<br />

Dacă se doreşte ca un program să afişeze date în două locaŃii diferite, folosind<br />

\;ză <strong>de</strong> date locală sau la distanŃă, se poate implementa o interfaŃă cu ajutorul<br />

.-iiului Abstract Factorv astfel:<br />

Bcneficii §'\ inconveniente<br />

l.'n sablon Abstract Factory ajuta la crestcrca pe ansamblu a flexibilitatii unei<br />

:catii. Aceasta flexibilitate se manifests atat in etapa <strong>de</strong> <strong>de</strong>sign cat si in cea <strong>de</strong><br />

^rc a aplicatiei. In timpul <strong>de</strong>sign-ului. trebuie sa se <strong>de</strong>cida viitoarele utilizari ale<br />

■.catiei. La rulare. aplicatiei fi pot fi usor integrate noi caracteristici si resurse.<br />

Un alt beneficiu al acestui sablon este acela ca el poate simplifica testarea<br />

v.ilui aplicatiei. Implementarea unor clase <strong>de</strong> test si anume TestConcreteFactory §i -<br />

:ConcreteProduct este simpla, putandu-se astfel simula comportamentul asteptat al<br />

.:rselor.<br />

Pentru a putea beneficia <strong>de</strong> acest sablon, trebuie <strong>de</strong>fmita cu atentie o interfata<br />

.erica corespunzatoare pentru produsul abstract. Daca produsul abstract e <strong>de</strong>finit<br />

Meet, realizarea unor produse concrete poate fi dificila sau chiar imposibila.<br />

\ ariante ale §ablonului<br />

Dupa cum s-a mentionat anterior, se pot <strong>de</strong>fini AbstractFactory si<br />

straetProduct ca interfete sau clase abstracte, in functie <strong>de</strong> necesitatile aplicatiei sau<br />

: v eferinte. Unele variante ale sablonului Abstract Factory permit producerea mai


.'.tor obiecte ConcreteFactory. rezultand o aplicatie care poate folosi simultan<br />

::!ii multiple <strong>de</strong> ConcreteProducts.<br />

Sabloane asociate<br />

Printre sabloanele asociate lui Abstract Factory se numara:<br />

- Factory Method<br />

- Singleton<br />

- Data Access Object<br />

Exemplu<br />

Daca se doreste ca un program sa afiseze date in doua locatii diferite, folosind<br />

\;za <strong>de</strong> date locala sau la distanta, se poate implementa o interfata cu ajutorul<br />

.-nului Abstract Factory astfel:<br />

r.~-;:rface ConnectionFactory {<br />

Local qetLocalConnection(); Remote<br />

getRemcteCor.nection ( ) ;<br />

\.;=s DataKanager implements ConnectionFactcry { boolean local = false;<br />

Datalnfo[] data; public Local ger.LocalConnection() {<br />

return new Local Mo<strong>de</strong>(); } public Remote<br />

getRemoteConnection() {<br />

return new RemoteMo<strong>de</strong>();<br />

public void loadData { ) { if(local){<br />

Local conn = getLccalConnection ( ) ; data = conn. ioadDB (<br />

"dlo.db"; ;<br />

.. r.z-:-,rface ConnectionFactory {<br />

Local qetLocalConnection(); Remote<br />

getRemcteCor.nection ( ) ;<br />

r-. ass DataKanager implements ConnectionFactcry { boolean local = false;<br />

Datalnfo[] data; public Local ger.LocalConnection() {<br />

return new Local Mo<strong>de</strong>(); } public Remote<br />

getRemoteConnection() {<br />

return new RemoteMo<strong>de</strong>();<br />

public void loadData { ) { if(local){<br />

Local conn = getLccalConnection ( ) ; data = conn. ioadDB (<br />

"dlo.db"; ;


II.2. Buil<strong>de</strong>r<br />

ProprietăŃi<br />

Scop<br />

telse {<br />

Rerr.ote conn = getRenoieConnecti ori (} ;<br />

conn . connect2WWW ( "v«w . sorr.e . vihere . con:'<br />

data = conn.loadDB("db.db");<br />

i<br />

)lic void setConnection(boolean b) { local = b;<br />

- Tip: creaŃional<br />

- Nivel: componentă<br />

Sa simplifice crearea obiectelor complexe prin <strong>de</strong>finirea unei clase al cărui<br />

-:e <strong>de</strong> a construi instanŃe ale altei clase. Şablonul Buil<strong>de</strong>r realizează un produs<br />

'dl în care. chiar dacă există mai multe clase, conŃine întot<strong>de</strong>auna o clasă<br />

Introducere<br />

în managerul personal <strong>de</strong> informaŃii, utilizatorii pot dori a lucra cu un calendar<br />

'.. Pentru aceasta trebuie <strong>de</strong>finită o clasă Appointment conŃinând informaŃii<br />

■J un singur eveniment, urmărind informaŃii precum:<br />

- date <strong>de</strong> început şi sfârşit ale întâlnirilor<br />

- o <strong>de</strong>scriere a întâlnirii<br />

- locaŃia întâlnirii<br />

- participanŃii la întâlnire<br />

Evi<strong>de</strong>nt, aceste informaŃii sunt introduse <strong>de</strong> un utilizator atunci când îşi<br />

jj./.ă o întâlnire, <strong>de</strong>ci trebuie <strong>de</strong>finit un constructor care să permită crearea unui<br />

'Mect <strong>de</strong> tip Appointment (întâlnire). Diferite informaŃii sunt necesare pentru<br />

JJ unui obiect întâlnire, <strong>de</strong>pinzând <strong>de</strong> tipul acesteia. Unele întâlniri presupun<br />

.Tiirea unei liste <strong>de</strong> participanŃi. Unele pot avea o dată <strong>de</strong> început şi una <strong>de</strong> sfârşit.<br />

pot avea o singură dată. Când sunt luate în consi<strong>de</strong>rare aceste opŃiuni, crearea<br />

:elor Appointment nu este trivială.<br />

Sunt doua posibilităŃi <strong>de</strong> creare a obiectelor, insa nici una din ele atractivă. Se<br />

rea constructori pentru fiecare tip <strong>de</strong> întâlnire în parte sau se poate scrie un<br />

: ..etor enorm cu o mare funcŃionalitate logică. Fiecare dintre aceste modalităŃi<br />

".convenienŃe - constructori mulŃi, logica <strong>de</strong>venind mult mai complexă. Mai rău<br />

.-*.. ambele modalităŃi creează probleme atunci când se încearcă implementarea -<br />

uhelase a clasei Appointment.


Daca însă responsabilitatea creării unei întâlniri e cedată unei clase speciale<br />

AppointmentBuil<strong>de</strong>r, atunci are loc simplificarea codului clasei Appointment.<br />

AppoinlmentBuil<strong>de</strong>r conŃine meto<strong>de</strong> <strong>de</strong> creare a părŃilor unei întâlniri, având nume<br />

sugestive. In plus. clasa AppointmentBuil<strong>de</strong>r asigură că informaŃiile introduse la<br />

crearea unei întâlniri sunt vali<strong>de</strong>.<br />

• Utilizare<br />

Şablonul Buil<strong>de</strong>r se foloseşte când o clasă:<br />

- are o structură internă complexă, în special una cu un set variabil <strong>de</strong> obiecte<br />

asociate<br />

- are atribute care <strong>de</strong>pind unele <strong>de</strong> altele. Unul din lucrurile pe care şablonul<br />

Buil<strong>de</strong>r îl poate face este să forŃeze construirea unui obiect complex<br />

- foloseşte alte obiecte ale sistemului care pot fi dificil <strong>de</strong> obŃinut în timpul<br />

creării<br />

• Descriere<br />

Deoarece şablonul se ocupă <strong>de</strong> construirea unui obiect complex din mai multe<br />

surse posibile şi diferite, el se numeşte Buil<strong>de</strong>r - constructor. Pe măsura ce crearea<br />

obiectelor creşte în complexitate, crearea obiectelor cu ajutorul constructorului poate<br />

<strong>de</strong>veni dificilă. Acest lucru se întâmplă <strong>de</strong> regulă când obiectul nu <strong>de</strong>pin<strong>de</strong> exclusiv<br />

<strong>de</strong> resursele care se află sub controlul său.<br />

Obiectele <strong>de</strong> tip afacere fac parte din această categorie. Ele necesită frecvent<br />

date dintr-o bază <strong>de</strong> date pentru a se iniŃializa, precum şi asocierea cu alte obiecte <strong>de</strong><br />

tip afacere pentru a reprezenta cât mai fi<strong>de</strong>l mo<strong>de</strong>lul <strong>de</strong> afacere. Un alt exemplu ar fi<br />

un obiect compus din sistem, cum ar fi obiectul care reprezintă un <strong>de</strong>sen într-un<br />

program vizual <strong>de</strong> editare. Un astfel <strong>de</strong> obiect trebuie asociat cu un număr arbitrar <strong>de</strong><br />

alte obiecte imediat ce este creat.<br />

In astfel <strong>de</strong> cazuri, este convenabilă <strong>de</strong>finirea unei alte clase care să fie<br />

responsabilă cu crearea. Şablonul Buil<strong>de</strong>r coordonează asamblarea obiectului produs:<br />

crează resurse, reŃine rezultate intermediare şi pune la dispoziŃie structura funcŃională<br />

a creării. In plus. el poate obŃine resurse <strong>de</strong> sistem necesare pentru construirea<br />

obiectului produs.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Buil<strong>de</strong>r este următoarea:<br />

Director<br />

-AbstractBuil<strong>de</strong>rf] buil<strong>de</strong>r<br />

+Product buildProductQ<br />

pentru fiecare parte a<br />

produsului buil<strong>de</strong>r.buildPartQ<br />

0..*<br />

ConcreteBuil<strong>de</strong>r<br />

+void buildPartQ<br />

+Product getProductQ<br />

inter face<br />

AbstractBuil<strong>de</strong>r<br />

+void buildPartQ<br />

creează. Product


Pentru implementarea şablonului Builer este nevoie <strong>de</strong>:<br />

- Director - are o referinŃă către o instanŃa AbstractBuil<strong>de</strong>r. Clasa Director<br />

apelează meto<strong>de</strong>le creaŃtionale pentru a construi diferite părŃi ale produsului, precum<br />

şi Buil<strong>de</strong>r-ul<br />

- AbstractBuil<strong>de</strong>r - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le <strong>de</strong> creare disponibile<br />

pentru crearea părŃilor diferite ale produsului<br />

- ConcreteBuil<strong>de</strong>r - implementează interfaŃa AbstractBuil<strong>de</strong>r. Implementează<br />

toate meto<strong>de</strong>le necesare creării unui obiect real <strong>de</strong> tip Product. Meto<strong>de</strong>le acestei clase<br />

ştiu cum să proceseze informaŃiile primite <strong>de</strong> la clasa Director şi să construiască<br />

părŃile respective ale obiectului Product. Clasa ConcreteBuil<strong>de</strong>r are <strong>de</strong> asemenea ori o<br />

metodă getProduct sau o metodă creatională care returneazâ instanŃa produsului<br />

- Product - obiectul rezultat. El poate fi <strong>de</strong>finit fie ca o clasă, fie ca o interfaŃă<br />

■ Beneficii şi inconveniente<br />

Pentru obiectele care necesită o creare în mai mulŃi paşi, Buil<strong>de</strong>r se comportă<br />

ca un obiect <strong>de</strong> nivel înalt care supervizează procesul. F,I poate coordona şi valida<br />

crearea tuturor resurselor şi dacă este nevoie pune Ia dispoziŃie o strategie <strong>de</strong> reluare a<br />

procesului în cazul apariŃiei unei erori. Pentru obiectele care au nevoie <strong>de</strong> resurse <strong>de</strong><br />

sistem în timpul creării, cum ar fi conexiuni cu baza <strong>de</strong> date sau obiecte <strong>de</strong> tip afacere<br />

<strong>de</strong>ja existente, Buil<strong>de</strong>r are un o modalitate convenabilă <strong>de</strong> control al acestor resurse.<br />

Principalul inconvenient al acestui şablon este acela că există o legătură<br />

strânsă între produse şi toate obiectele create în timpul construirii acestora. Prin<br />

urmare, schimbări care apar în produsul creat <strong>de</strong> Buil<strong>de</strong>r conduc <strong>de</strong> regulă şi la<br />

modificări ale Buil<strong>de</strong>r-ului.<br />

■ Variante ale şablonului<br />

Este posibilă implementarea mai multor şabloane Buil<strong>de</strong>r în jurul unei singure<br />

clase Buil<strong>de</strong>r. Pentru o mai mare flexibilitate, se poate extin<strong>de</strong> acest şablon <strong>de</strong> bază<br />

prin una sau mai multe din următoarele posibilităŃi:<br />

- se creează un şablon Buil<strong>de</strong>r abstract. Prin <strong>de</strong>finirea unei clase sau interfeŃe<br />

care să specifice meto<strong>de</strong>le <strong>de</strong> creare, se poate produce un sistem mult mai generic care<br />

poate găzdui diferite tipuri <strong>de</strong> Buil<strong>de</strong>re<br />

- se <strong>de</strong>finesc meto<strong>de</strong> ereaŃionalc multiple pentru Buil<strong>de</strong>r. Unele Buil<strong>de</strong>re<br />

<strong>de</strong>finesc meto<strong>de</strong> multiple pentru a pune la dispoziŃie o mai marc varietate <strong>de</strong> moduri<br />

<strong>de</strong> iniŃializare a resurselor necesare<br />

- se <strong>de</strong>zvoltă <strong>de</strong>legaŃi creaŃionali. Astfel, un obiect <strong>de</strong> tipul Director conŃine<br />

metoda <strong>de</strong> creare ale produsul general şi apelează o serie <strong>de</strong> meto<strong>de</strong> crcaŃionale ale<br />

obiectului Buil<strong>de</strong>r. In acest caz, Obiectul Director se comportă ca manager al<br />

:esului <strong>de</strong> creare al Buil<strong>de</strong>r-ului<br />

■ Şabloane asociate<br />

Printre şabloanele asociate se numără şablonul Composite. De multe<br />

ori . donul Buil<strong>de</strong>r este folosit pentru a produce obiecte <strong>de</strong> tip Composite care au o .<br />

jetură foarte complexă.<br />

• Exemplu<br />

Se poate folosi §ablonul Buil<strong>de</strong>r pentru crearea unui produs complex, <strong>de</strong><br />

.'.xemplu o mtalnire:


. ■ - - 2 class /ippoir tmGnt Bui 1 <strong>de</strong> r {<br />

public static final int START_DATE_REQUIRED =■ 1; public static final<br />

int END_ DATE_RF,QU1RED = 2; public static final int<br />

DESCRTPTION__REQUIRED = 4; public static final int<br />

ATTENDEE_REQUIRED = 8; public static final int<br />

LOCATION_REQUIRED = 16; protected Appointment appointment;<br />

protected int requiredElements; public void buildAppointment () {<br />

appointment = new Appointment();<br />

public void buildDates(Date starcDate, Dare endDate) { Date currentDate = new<br />

Date(); if ( (startDate i= null) && (startDate.after (currentDate))) {<br />

appointment.setstartDate(startDate); }<br />

if ((endDate != null) && (endDate.after (startDate))) {<br />

appointment.setEndDate(endDate); }<br />

public void buildDescriution(String newDescription) {<br />

appointment.setDescription(newDescription);<br />

public void build-Atten<strong>de</strong>es (ArrayList atten<strong>de</strong>es) {<br />

if ((atten<strong>de</strong>es != null) && (!atten<strong>de</strong>es.isEmpty())) {<br />

appointment.setAtten<strong>de</strong>es(atten<strong>de</strong>es); }<br />

public void buildLocation(Location newLocation) { if (newLocation !=<br />

null) {<br />

appointment.setLocation(newLocation); }<br />

}<br />

public Appointment getAppointment() throws<br />

Inf orrriationRequiredException { requiredElements = 0; rf<br />

(appointment.getStartDate() == null) {<br />

requiredElements += START_DATE_REQUIRED; } if<br />

(appointment.getLocation() == null) {<br />

requiredElements += LOCATION_REQUIRED; } if<br />

(appointment.getAtten<strong>de</strong>es().isEmpty()) {<br />

requiredElements += ATTENDEE_REQUIRED; } if<br />

(requiredElements > 0) {<br />

throw new InformationRequiredException<br />

(requiredElements); } return<br />

appointment;<br />

public int getRequiredElements() { return<br />

requiredElements;<br />

II.3. Factory Method<br />

• Cunoscut şi ca Virtual Constructor<br />

• ProprietăŃi<br />

Scop<br />

- Tip: creaŃional<br />

- Nivel: clasă<br />

Să <strong>de</strong>finească o metodă standard <strong>de</strong> creare a unui obiect, diferită <strong>de</strong> un<br />

constructor, lăsând însă subclasei alegerea tipului obiectului ce urmează a fi creat.<br />

• Introducere<br />

Presupunem că se lucrează cu un manager personal <strong>de</strong> informaŃii. Acesta va<br />

conŃine multe bucăŃi <strong>de</strong> informaŃii esenŃiale vieŃii <strong>de</strong> zi cu zi: adrese, întâlniri, date,<br />

cărŃi citite şi altele. Aceste informaŃii nu sunt statice; <strong>de</strong> exemplu trebuie să se poată<br />

modifica adresa a unei persoane atunci când aceasta se mută sau să se modifice<br />

<strong>de</strong>taliile unei întâlniri dacă persoana <strong>de</strong> contact întârzie.


Managerul personal <strong>de</strong> informaŃii e responsabil <strong>de</strong> modificarea fiecărui câmp.<br />

Marele <strong>de</strong>zavantaj este acela că el trebuie să cunoască toate tipurile <strong>de</strong> întâlniri<br />

precum şi modificările care se pot face asupra lor. Fiecare articol conŃine diferite<br />

câmpuri şi utilizatorul trebuie să vadă un ecran <strong>de</strong> intrare apropiat acestor câmpuri.<br />

Devine foarte greu <strong>de</strong> introdus informaŃii <strong>de</strong>spre noile tipuri <strong>de</strong> sarcini pentru că<br />

trebuie adăugată managerului personal <strong>de</strong> informaŃii o noua capacitate <strong>de</strong> editare <strong>de</strong><br />

fiecare dată. potrivită pentru modificarea noului tip <strong>de</strong> articol. Mai mult. fiecare<br />

schimbare apărută într-o sarcina specifică, cum ar fi adăugarea unui câmp nou unei<br />

întâlniri, înseamnă modificarea managerului astfel încât el să recunoască noul câmp.<br />

Se ajunge la un manager personal <strong>de</strong> informaŃii foarte încâlcit şi greu <strong>de</strong> întreŃinut.<br />

SoluŃie este lăsarea articolelor, ca întâlnirile, să fie responsabile cu punerea la<br />

dispoziŃie a propriilor editoare pentru administrarea adăugărilor şi modificărilor.<br />

Managerul <strong>de</strong> informaŃii trebuie doar să ştie cum să ceară un anumit editor folosind<br />

metoda getEditor. care se afla în fiecare articol ce poate fi editat. Metoda returnează<br />

un obiect care implementează interfaŃa ItemEditor. managerul urmând a utiliza acest<br />

obiect pentru a cere o componenta JComponent sau un editor GUI. Utilizatorii pot<br />

modifica informaŃiile articolului pe care doresc sa-1 editeze şi editorul asigură că<br />

schimbările sunt aplicate corect.<br />

Toate informaŃiile <strong>de</strong>spre cum trebuie editat un anumit articol sunt conŃinute în<br />

editor, care este pus la dispoziŃie <strong>de</strong> articolul însăşi. Reprezentarea grafică a editorului<br />

este <strong>de</strong> asemenea creată <strong>de</strong> editor. Acum se pot introduce noi tipuri <strong>de</strong> articole fără a<br />

fi nevoie <strong>de</strong> modificarea managerului personal <strong>de</strong> informaŃii.<br />

• Utilizare<br />

Şablonul Factory Method se foloseşte când:<br />

- se doreşte o flexibilitate mai mare prin lăsarea anumitor <strong>de</strong>cizii, cum ar fi<br />

cele privind tipul obiectului ce trebuie creat, pe mai târziu<br />

11


- se doreşte ca o subclasa şi nu supraclasa ei. să <strong>de</strong>cidă ce tip <strong>de</strong> obiect trebuie<br />

creat<br />

- se ştie când trebuie creat un obiect dar nu se ştie lipul acestuia<br />

- este nevoie <strong>de</strong> câŃiva constructori suprascrişi care au aceeaşi listă <strong>de</strong><br />

parametri, lucru nepermis în Java. în schimb, se folosesc câteva şabloane Factory<br />

Method cu nume diferite<br />

■ Descriere<br />

Acest şablon este numit Factory Method pentru că el creează obiecte atunci<br />

când se doreşte acest lucru. Când se începe scrierea unei aplicaŃii, <strong>de</strong> multe ori nu este<br />

clar ce tipuri <strong>de</strong> componente o să se utilizeze. în mod normal există o i<strong>de</strong>e generală<br />

<strong>de</strong>spre operaŃiile pe care urmează să le facă anumite componente, dar implementarea<br />

se face ulterior şi nu reprezintă consecinŃa acelui moment.<br />

Flexibilitatea poate fi obŃinută utilizând interfeŃe pentru aceste componente.<br />

Dar problema programării cu interfeŃe este aceea că nu se pot crea obiecte dintr-o<br />

interfaŃă. Trebuie să existe o clasă implementată pentru a obŃine un obiect. In loc <strong>de</strong> a<br />

codifica o clasă specifică implementată în aplicaŃie, se extrage funcŃionalitatea<br />

constructorului şi se introduce într-o metodă. Aceasta metodă este Factory Method. Se<br />

creează astfel o clasa ConcreteCreator a cărei responsabilitate este <strong>de</strong> a crea obiectele<br />

corecte. Clasa ConcreteCreator creează instanŃe ale implementării - ConcreteProduct -<br />

unei interfeŃe - Product.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Factory Method este următoarea:<br />

interface Creator<br />

+Product facioryMethodQ<br />

ConcreteCreator<br />

+Product factoryMethodQ<br />

return nevv ConcreteProductQ<br />

instanŃia/.ă<br />

interface Product<br />

ConcreteProduct<br />

Pentru implementarea şablonului Factory Method este nevoie <strong>de</strong>:<br />

- Product - interfaŃa obiectelor create <strong>de</strong> şablon<br />

- ConcreteProduct - clasa care implementează interfaŃa Product. Obiectele<br />

acestei clase sunt create <strong>de</strong> clasa ConcreteCreator


- Creator - interfaŃa ce <strong>de</strong>fineşte metoda iactorvMethod<br />

- ConcreteCreator - clasa ce extin<strong>de</strong> clasa Creator şi conŃine implementarea<br />

meto<strong>de</strong>i factoryMethod. Ea poate returna orice obiect care implementează interfaŃa<br />

Product<br />

Beneficii şi inconveniente<br />

Un beneficiu major este acela că managerul personal <strong>de</strong> informaŃii poate fi<br />

foarte generic. Trebuie doar să ştie cum să ceară un editor pentru un articol.<br />

InformaŃia privind modul <strong>de</strong> editare al unui articol specific este conŃinută în editor.<br />

Editorul poate <strong>de</strong> asemenea crea interfaŃa grafică cu utilizatorul pentru editare. Acest<br />

lucru face managerul <strong>de</strong> informaŃii mult mai uşor <strong>de</strong> utilizat, putându-se introduce noi<br />

tipuri <strong>de</strong> informaŃii fără a fi nevoie <strong>de</strong> modificarea programului central.<br />

Inconvenientul acestui şablon este acela că pentru a adăuga un nou tip <strong>de</strong><br />

produs, trebuie adăugată şi implementată o nouă clasă şi trebuie ori modificată o clasă<br />

ConcreteCreator <strong>de</strong>ja existentă ori creată o nouă clasă care să implementeze interfaŃa<br />

Product.<br />

• Variante ale şablonului<br />

Există mai multe variante ale şablonului Factory Method:<br />

- clasa Creator poate avea o implementare standard pentru meto<strong>de</strong>le <strong>de</strong> tip<br />

factoryMethod. In acest fel, clasa Creator nu trebuie să fie o clasă abstractă sau o<br />

interfaŃă. Beneficiul este acela că nu trebuie implementată o subclasa a clasei Creator<br />

- interfaŃa Product poate fi implementată ca o clasă abstractă, astfel putând fi<br />

adăugate implementări pentru alte meto<strong>de</strong><br />

- metoda factoryMethod poate avea un parametru. Poate apoi crea mai multe<br />

tipuri <strong>de</strong> obiecte Product pe baza parametrului dat. Acest lucru duce la scă<strong>de</strong>rea<br />

meto<strong>de</strong>lor <strong>de</strong> tip factoryMethod necesare.<br />

• Şabloane asociate<br />

Printre şabloanele asociate şablonului Factory Method se află:<br />

- Prototype - evită implementarea unei subclase a clasei Creator<br />

- Template Method - meto<strong>de</strong>le <strong>de</strong> tip Template apelează <strong>de</strong> regulă meto<strong>de</strong> <strong>de</strong><br />

tip factoryMethod<br />

- Data Access Object - foloseşte şablonul Factory Method pentru a putea crea<br />

instanŃe specifice ale obiectelor <strong>de</strong> tip Data Access Objects fără a necesita cunoştinŃe<br />

<strong>de</strong>spre baza <strong>de</strong> date specifică<br />

■ Exemplu<br />

Şablonul Factory Method poate fi folosit pentru realizarea unei picturi, după<br />

cum urmează:<br />

13


î n t e r r ci L.. e o h d o e \<br />

public voia craw(;; }<br />

dass Line impiements Shape {<br />

Point x, y;<br />

Line(Point a, Foint b; { x = a; y = b; }<br />

public voj.d drawŃ; { //se <strong>de</strong>senează o linie } }<br />

dass Square implemerits Shape {<br />

Point start;<br />

int width, height;<br />

Square (Point s, irit w, int. h) {<br />

start = s ; w i d t h = w ; height<br />

= h;<br />

}<br />

public void drawŃ) { //se <strong>de</strong>senează un pătrat }<br />

}<br />

d a s s P a i n t in g {<br />

Point x, y;<br />

int width, height, radius; Painting(Point a,<br />

Point b, int w, int h, int r)<br />

x = a;<br />

y = b;<br />

width = w;<br />

neight = h;<br />

radius = r;<br />

Shape pic;<br />

Painting pt;<br />

Shape drawLine Ń) {<br />

return new Line(x,y);<br />

Shace drawSquare ( ) {<br />

return new Square(x, width, height);<br />

ii (line) pic = pt.drawLine(); if<br />

(square) pic = pt.drawSquare()<br />

II.4. Prototype •<br />

ProprietăŃi<br />

• Scop<br />

- Tip: creaŃional<br />

- Nivel: clasă unică<br />

Să facă crearea dinamică mai uşoară prin <strong>de</strong>finirea <strong>de</strong> clase ale căror obiecte se<br />

pot duplica.<br />

14


• Introducere<br />

In managerul personal <strong>de</strong> informaŃii, se doreşte copierea unei adrese astfel<br />

încât utilizatorul să nu fie nevoit să introducă manual toate informaŃiile atunci când<br />

creează un nou contact. O modalitate <strong>de</strong> rezolvare a acestei situaŃii presupune<br />

următorii paşi:<br />

- crearea unui nou obiect <strong>de</strong> tip Address<br />

- copierea valorilor apropiate din obiectul <strong>de</strong> tip Address existent<br />

Cu toate că acesta abordare rezolvă problema, ea are un mare inconvenient -<br />

încalcă principiul încapsulării. Pentru a aplica soluŃia <strong>de</strong> mai sus, trebuie introduse<br />

apelări ale meto<strong>de</strong>lor pentru a copia informaŃiile din clasa Address în afara ei. Acest<br />

lucru duce la îngreunarea întreŃinerii codului clasei Address. Este <strong>de</strong> asemenea dificilă<br />

reutilizarea clasei Address în alte proiecte.<br />

Deoarece codul ce se doreşte copiat aparŃine clasei Address, se pot evita<br />

greutăŃile întâmpinate prin <strong>de</strong>finirea unei meto<strong>de</strong> <strong>de</strong> copiere în clasă. Această metodă<br />

produce un duplicat al obiectului <strong>de</strong> tip Address cu aceleaşi date ca şi obiectul<br />

original. Apelarea meto<strong>de</strong>i printr-un obiect <strong>de</strong> tip Address existent rezolvă problema<br />

într-o manieră mai bună şi mai apropiată <strong>de</strong> regulile programării orientate pe obiecte.<br />

• Utilizare<br />

Şablonul Prototype se foloseşte pentru crearea unui obiect care este copia unui<br />

obiect <strong>de</strong>ja existent.<br />

• Descriere<br />

Numele acestui şablon este sugestiv; el foloseşte un obiect drept prototip<br />

pentru a crea o nouă instanŃă a lui cu aceleaşi valori. El permite programelor să<br />

execute operaŃii cu copia unui obiect şi să iniŃializeze obiectele într-o stare care a fost<br />

stabilită prin utilizarea sistemului. Acest lucru este <strong>de</strong> multe ori preferabil iniŃializerii<br />

obiectului cu un set generic <strong>de</strong> valori.<br />

Exemple clasice pentru acest şablon se regăsesc în editoarele grafice şi <strong>de</strong> text,<br />

un<strong>de</strong> funcŃiile <strong>de</strong> copiere şi lipire pot îmbunătăŃi productivitatea utilizatorilor. Unele<br />

sisteme <strong>de</strong> afaceri folosesc aceeaşi modalitate, producând un mo<strong>de</strong>l iniŃial pe baza<br />

unui obiect existent, mo<strong>de</strong>l ce poate fi apoi modificat în funcŃie <strong>de</strong> noile cerinŃe.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Prototype este următoarea:<br />

Client<br />

+void operationQ<br />

Prototype p = new prototype.copy()<br />

Prototype<br />

+Prottotype copy()<br />

15


Pentru implementarea şablonului Prototype este nevoie <strong>de</strong>:<br />

- Prototype - conŃine metoda <strong>de</strong> copiere. Metoda întoarce o instanŃă a aceleaşi<br />

clase cu aceleaşi valori ca şi instanŃa originală. Noua instanŃă poate fi o copie fi<strong>de</strong>lă<br />

sau superficială a celei originale<br />

• Beneficii şi inconveniente<br />

Şablonul Prototype este folositor <strong>de</strong>oarece permite sistemelor să producă o<br />

copie a unui obiect utilizat, cu variabile <strong>de</strong>ja setate la anumite valori, iară a <strong>de</strong>pin<strong>de</strong><br />

<strong>de</strong> cele <strong>de</strong>finite în constructor.<br />

O copie superficiala face duplicatul doar a elementelor principale ale clasei;<br />

astfel se obŃine o copie mai rapidă dar care poate să nu acopere toate necesităŃile.<br />

Deoarece caracteristicile sunt copiate din original, copia indică tot obiectul iniŃial.<br />

Prin urmare modificarea unui astfel <strong>de</strong> obiect afectează toate copiile.<br />

OperaŃiile <strong>de</strong> copiere în adâncime fac duplicatul tuturor caracteristicilor unui<br />

obiect. Acestea durează <strong>de</strong> regulă mai mult <strong>de</strong>cât copierile superficiale şi pot fi foarte<br />

costisitoare pentru obiectele care au o structură complexă. Acest lucru asigură faptul<br />

că modificările într-o copie sunt izolate <strong>de</strong> alte copii.<br />

• Variante ale şablonului<br />

Variantele şablonului Prototype includ:<br />

- Copy Constructor - acest constructor <strong>de</strong> copiere ia o instanŃă a aceleaşi clase<br />

ca argument şi returnează o nouă copie cu aceleaşi valori ca şi argumentul. Beneficiul<br />

acestei variante este aceea că intenŃia <strong>de</strong> a crea o noua instanŃă este clară dar o<br />

singură modalitate <strong>de</strong> copiere poate fi executată.<br />

- Clone Method - limbajul Java <strong>de</strong>fineşte o metodă <strong>de</strong> donare în clasa<br />

java.lang.Object - supraclasa tuturor claselor Java. Pentru ca metoda să poată fi<br />

utilizată într-o instanŃă, clasa obiectului respectiv trebuie să implementeze interfaŃa<br />

java.lang.Clonable pentru a indica că o instanŃă a acestei clase poate fi copiată<br />

■ Şabloane asociate<br />

Printre şabloanele asociate şablonului Prototype se afla:<br />

- Abstract Factory - poate folosi şablonul Prototype pentru a crea noi obiecte<br />

bazate pe cele aflate în uz<br />

- Factory Method - poate folosi şablonul Prototype ca un template pentru noile<br />

obiecte<br />

• Exemplu<br />

Un exemplu <strong>de</strong> şablon Prototype este chiar suprascrierea unei meto<strong>de</strong>:<br />

interface Shape {<br />

public void draw();<br />

i<br />

class Line implements Shape {<br />

public void draw() { System.out.println("line"); } }<br />

16


c_i_ass bquare : nplenenus Sna". e ■,<br />

pudic voi ci draw j ; { "yc .:-::.. : u~. . p r .ir.t In ( "squar e" ) ; }<br />

L<br />

J<br />

class Circle irr.plerrents Shapc- {<br />

public void draw() ; Systcr,.cur.priritInŃ"circle"); }<br />

class Paintina {<br />

public sr_a~ic void .tain ( Suriri g [ J args; {<br />

Shape si ~- nev» L i n e ( ) ;<br />

Shape s2 = nes Square();<br />

Shape s3 = new Circle ( ) ;<br />

oaint; ( si} ;<br />

painr(s2);<br />

paint ( s3} ; } static<br />

void paint(Shape s) {<br />

if (s instanceof Line) s.drawŃ)<br />

if (s instanceof Square) s.draw<br />

if îs insranceof Circle) s.draw<br />

II.5. Singleton<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: creaŃional<br />

- Nivel: obiect<br />

Să existe doar o singură instanŃă a acestei clase în sistem, permiŃând altor clase<br />

acces la această instanŃă.<br />

■ Introducere<br />

Din când în când este nevoie <strong>de</strong> un obiect global, unul care să fie accesibil <strong>de</strong><br />

oriun<strong>de</strong> dar care să fie creat o singură dată. Se doreşte ca toate părŃile aplicaŃiei să<br />

poată utiliza obiectul folosind aceeaşi instanŃă. Un exemplu ar fi un istoric - o listă <strong>de</strong><br />

acŃiuni pe care le-a tăcut utilizatorul în timpul lucrului cu aplicaŃia. PărŃi multiple ale<br />

aplicaŃiei folosesc acelaşi obiect HistoryList, fie pentru a adăuga o acŃiune a<br />

utilizatorului fie pentru a şterge acŃiuni anterioare. O modalitate <strong>de</strong> a face acest lucru<br />

este crearea unui obiect global <strong>de</strong> către aplicaŃie, urmând ca fiecare obiect care are<br />

nevoie <strong>de</strong> el să aibă o referinŃă către obiectul global. Totuşi, poate fi foarte dificil <strong>de</strong><br />

<strong>de</strong>terminat cum să se trimită această referinŃă şi ce părŃi ale aplicaŃiei au nevoie <strong>de</strong><br />

acest obiect.<br />

O altă cale este <strong>de</strong> a crea valori globale folosind variabile statice. AplicaŃia ar<br />

avea câteva obiecte statice în interiorul unei clase pe care le va accesa direct. Dar şi<br />

această abordare are câteva inconveniente. Un obiect static nu este suficient <strong>de</strong>oarece<br />

el va fi creat atunci când clasa se încarcă, nelăsând astfel nici o oportunitate <strong>de</strong> a<br />

introduce date înainte <strong>de</strong> instanŃiere. Aici intra în joc şablonul Singleton. El permite<br />

accesul uşor al întregii aplicaŃii la obiectul global.<br />

17


• Utilizare<br />

Şablonul Singleton se foloseşte când se doreşte o singură instanŃa a unei clase<br />

care sa fie disponibilă peste tot.<br />

■ Descriere<br />

Şablonul Singleton asigură crearea unei singure instanŃe <strong>de</strong> către JVM. Pentru<br />

a fi siguri că <strong>de</strong>Ńinem controlul asupra instanŃtierii, constructorul trebuie <strong>de</strong>clarat<br />

privat. Apare însă o problemă: este imposibil <strong>de</strong> creat o instanŃă, astfel că o metoda <strong>de</strong><br />

acces este pusă la dispoziŃie <strong>de</strong> o metodă statică getlnstanceQ. Această metodă<br />

creează o singură instanŃă, dacă nu există <strong>de</strong>ja, şi returnează referinŃa singleton-ului<br />

celui care apelează metoda. ReferinŃa către singleton este stocată ca un atribut static<br />

privat al clasei singleton-ului pentru viitoare apelări.<br />

Cu toate că metoda <strong>de</strong> acces poate crea singleton-ul. <strong>de</strong> cele mai multe ori el<br />

este creat atunci când clasa este încărcată. întârzierea construcŃiei este necesară doar<br />

dacă o anumită formă <strong>de</strong> iniŃializare trebuie făcuta înainte ca singleton-ul sa fie<br />

instanŃiat.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Singleton este următoarea:<br />

Singleton<br />

-Sinaleton instance = new SinaJetonO<br />

-SingletonŃ) +Singleton<br />

gctlnstanceQ<br />

return instance<br />

Pentru implementarea şablonului Singleton este nevoie <strong>de</strong>:<br />

- Singleton - clasa ce conŃine un constructor privat, menŃine o referinŃă statică<br />

privată către singura instanŃă a acestei clase şi pune la dispoziŃie o metodă <strong>de</strong> acces<br />

statică care returnează referinŃa către singura instanŃă<br />

• Beneficii şi inconveniente<br />

Şablonul Singleton este singura clasă ce-şi poate crea o instanŃă. Nu se poate<br />

crea o astfel <strong>de</strong> instanŃa fără utilizarea meto<strong>de</strong>i statice puse la dispoziŃie. Nu este<br />

nevoie a se trimite referinŃa către toate obiectele care folosesc acest singleton.<br />

Totuşi. în funcŃie <strong>de</strong> implementare, pot apărea probleme ale firelor <strong>de</strong> execuŃie.<br />

Trebuie avut mare grijă atunci când se iniŃializează un singleton într-o aplicaŃie cu<br />

multiple fire <strong>de</strong> execuŃie. Fără un control a<strong>de</strong>cvat, aplicaŃia poate conduce la un<br />

"război" al firelor <strong>de</strong> execuŃie.


• Variante ale şablonului<br />

Una dintre opŃiunile şablonului Singleton. <strong>de</strong> multe ori nebăgată în seama, este<br />

aceea <strong>de</strong> a avea mai mult <strong>de</strong> o instanŃă într-o clasă. Beneficiul este că restul aplicaŃiei<br />

poate rămâne la fel. în timp ce acelea care ştiu <strong>de</strong> aceste instanŃe multiple pot utiliza<br />

alte meto<strong>de</strong> pentru o obŃine alte instanŃe.<br />

Metoda <strong>de</strong> acces a singleton-ului poate fi punctul <strong>de</strong> intrare către un set <strong>de</strong><br />

instanŃe, toate <strong>de</strong> un subtip diferit. Metoda <strong>de</strong> acces poate <strong>de</strong>termina la rulare ce subtip<br />

specific <strong>de</strong> instanŃă să returneze. Acest lucru poate părea ciudat, dar este foarte<br />

folositor atunci când se utilizează clase dinamice. Sistemul care foloseşte singleton-ul<br />

rămâne neschimbat, în timp ce implementarea specifică a singleton-ului poate fi<br />

diferită.<br />

• Şabloane asociate<br />

Printre şabloanele asociate Singleton-ului se număra:<br />

- Abstract Factory<br />

- Buil<strong>de</strong>r<br />

- Prototype<br />

• Exemplu<br />

unica:<br />

Şablonul Singleton se poate utiliza pentru crearea unei conexiuni la distanŃă<br />

final class KemoteConnection {<br />

private Connect con;<br />

privare static RemoteConnecticn re = nev;<br />

RemoteConnection(connection) ; private<br />

RemoteConnection(Connect c) { con = c;<br />

public static RemoteConnection getRemoteConnection ( ) {<br />

return re; } public void<br />

setConnection(Connect c) f<br />

this(c);<br />

\<br />

19


III. Şabloane comportamentale<br />

Şabloanele comportamentale se concentrează pe controlul dintr-un sistem.<br />

Unele căi <strong>de</strong> organizare a controlului într-un sistem pot aduce beneficii mari atât în<br />

ceea ce priveşte eficienŃa cât şi în mentenanŃa sistemului.<br />

III.l. Chain Of Responsibility<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: componentă<br />

Să stabilească un lanŃ în sistem astfel încât un mesaj să poată fi utilizat la<br />

nivelul la care a fost primit sau să fie direcŃionat către un obiect care îl poate folosi.<br />

• Introducere<br />

Managerul personal <strong>de</strong> informaŃii poate fi folosit şi pentru managementul<br />

proiectelor. El poate fi văzut ca o structură arborescentă <strong>de</strong> sarcini. O sarcină este<br />

rădăcina arborelui, reprezentând proiectul însuşi. Sarcina <strong>de</strong> bază are un set <strong>de</strong><br />

subsarcini, fiecare din acestea având la rândul lor un set <strong>de</strong> subsarcini, şi aşa mai<br />

<strong>de</strong>parte. In acest fel, proiectul poate fi împărŃit într-un set <strong>de</strong> obiective legate între ele.<br />

Cum se lucrează cu informaŃiile dintr-o astfel <strong>de</strong> structură? De exemplu, ar fi<br />

<strong>de</strong> ajutor să se poată ve<strong>de</strong>a cine e responsabil pentru un anumit set <strong>de</strong> sarcini. Cum se<br />

atribuie grupuri <strong>de</strong> sarcini cuiva sau cum se trec sarcini altcuiva?<br />

O modalitate este <strong>de</strong>finirea unui atribut pentru fiecare sarcină care să<br />

reprezinte persoana care o în<strong>de</strong>plineşte. Când aceasta se schimbă, toate sarcinile şi<br />

subsarcinile sunt modificate încât să conŃină numele noii persoane care le execută.<br />

Insă această cale <strong>de</strong> reŃinere a persoanei răspunzătoare <strong>de</strong> o anumită sarcină este<br />

ineficientă, necesitând înregistrarea unei cantităci mari <strong>de</strong> informaŃii. O alternativă<br />

este referinŃa către unul sau mai multe obiecte centrale care reŃin numele<br />

responsabililor <strong>de</strong> sarcini. Cu toate că această abordare utilizează mult mai eficient<br />

memoria, ea necesită multă muncă pentru a realiza legăturile dintre sarcini şi obiectele<br />

centrale folosite pentru reŃinerea datelor.<br />

Ce se întâmplă însă atunci când se foloseşte arborele <strong>de</strong> sarcini însuşi pentru<br />

managementul responsabililor <strong>de</strong> sarcini? Se <strong>de</strong>fineşte o metodă în clasa sarcinii<br />

numită getOwner, care atunci când este apelată, verifică dacă responsabilul a fost<br />

specificat şi-i returnează numele în caz afirmativ. In caz contrar, sarcina apelează<br />

metoda getOwner a sarcinii părinte a sa. Această soluŃie necesită mai puŃină muncă<br />

<strong>de</strong>cât în ambele cazuri <strong>de</strong> mai sus şi rămâne eficientă şi în ceea ce priveşte utilizarea<br />

memoriei. Responsabilul <strong>de</strong> sarcini trebuie specificat doar într-o singură locaŃie a<br />

arborelui. Obiectele <strong>de</strong> tip Task fac restul muncii, predând apelul meto<strong>de</strong>i getOwner<br />

sarcinilor părinte ale lor până când este găsită una ce conŃine informaŃii. Acesta e un<br />

exemplu al şablonului Chain Of Responsibility.<br />

20


• Utilizare<br />

Şablonul Chain Of Responsibility se foloseşte când:<br />

- există un grup <strong>de</strong> obiecte în sistem care pot răspun<strong>de</strong> la acelaşi tip <strong>de</strong> mesaj<br />

- mesajele trebuie folosite <strong>de</strong> unul din obiectele din sistem<br />

- mesajele folosesc mo<strong>de</strong>lul "folosire sau trimitere mai <strong>de</strong>parte", adică unele<br />

mesaje pot fi utilizate la nivelul un<strong>de</strong> au fost recepŃionate sau produse, în timp ce<br />

altele trebuie trimise mai <strong>de</strong>parte către alte obiecte<br />

■ Descriere<br />

Când unele acŃiuni au loc într-un sistem orientat pe obiecte, acestea sunt <strong>de</strong><br />

regulă reprezentate printr-un eveniment sau mesaj. Un astfel <strong>de</strong> mesaj poate lua forma<br />

unei meto<strong>de</strong> care e apelată sau poate fi un obiect al sistemului. Mesajul este apoi<br />

direcŃionat către un alt obiect care poate răspun<strong>de</strong> sau utiliza mesajul. In cele mai<br />

simple cazuri, acelaşi obiect care produce mesajul, răspun<strong>de</strong> la el. De exemplu, un<br />

câmp un<strong>de</strong> se introduce un text poate produce un eveniment ca răspuns la acŃiunea<br />

utilizatorului - cum ar fi tastarea.<br />

In cele mai complexe cazuri, răspunsul la mesaje implică mai multe lucruri.<br />

Un mesaj care cere o modificare în apariŃia interfeŃei grafice cu utilizatorul poate fi<br />

analizat la mai multe niveluri. Dacă cererea este aceea <strong>de</strong> a se modifica aliniamentul<br />

textului dintr-un câmp. componenta însăşi poate răspun<strong>de</strong>. însă o cerere <strong>de</strong><br />

schimbarea a aliniamentului întregului text va fi probabil direcŃionată către nişte<br />

obiecte <strong>de</strong> nivel înalt.<br />

Şablonul Chain Of Responsibility reprezintă un lanŃ pentru mesaje. Dacă un<br />

obiect nu poate răspun<strong>de</strong> la un mesaj primit, el trimite mesajul mai <strong>de</strong>parte către alt<br />

obiect. în mod frecvent, şablonul Chain Of Responsibility este implementat după un<br />

mo<strong>de</strong>l părinte-fiu. Astfel, mesajele ce nu pot fi utilizate <strong>de</strong> către fiu sunt trimise<br />

părintelui, şi aşa mai <strong>de</strong>parte dacă este cazul, până când este întâlnit un obiect ce<br />

poate răspun<strong>de</strong> mesajului. Şablonul Chain Of Responsibility este potrivit pentru o<br />

varietate mare <strong>de</strong> activităŃi efectuate cu o interfaŃă grafică cu utilizatorul orientată pe<br />

obiecte. FuncŃiile <strong>de</strong> ajutor, structura componentelor, formatare şi poziŃionare<br />

cuprinse în interfaŃa grafica pot folosi acest şablon.<br />

■ Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Chain Of Responsability este următoarea:<br />

Client<br />

interface Handler<br />

void handleMessage ()<br />

ConcreteHandler<br />

-Handler handler<br />

+void handleMessageQ<br />

+void handlerMethod()<br />

if(can handle)<br />

handlerMethodQ<br />

else<br />

succesor.handleMessage()<br />

21


Pentru implementarea şablonului Chain Of Responsibility este nevoie <strong>de</strong>:<br />

- Handler - interfaŃa ce <strong>de</strong>fineşte metoda folosită pentru trimiterea mesajului<br />

către următorul Handler. Acest mesaj reprezintă <strong>de</strong> regulă doar apelarea meto<strong>de</strong>i, dar<br />

în cazul în care o cantitate mai mare <strong>de</strong> date trebuie încapsulată, poate fi trimis <strong>de</strong><br />

asemenea şi un obiect<br />

- ConcreteHandler - clasa care implemetează interfaŃa Handler. Ea păstrează o<br />

referinŃă către următoarea instanŃă către Handler. Această referinŃă este fie conŃinută<br />

în constructorul clasei sau într-o metodă proprie. Implementarea meto<strong>de</strong>i<br />

handleMessage poate <strong>de</strong>termina cum să se folosească metoda, cum să se apeleze<br />

metoda handleMethod şi cum să se trimită mesajul către următorul Handler<br />

■ Beneficii şi inconveniente<br />

Şablonul Chain Of Responsibility oferă flexibilitate mare în procesarea<br />

evenimentelor pentru o aplicaŃie, <strong>de</strong>oarece oferă posibilitatea <strong>de</strong> management a unor<br />

evenimente complexe prin împărŃirea responsabilităŃilor între un număr <strong>de</strong> elemente<br />

simple. Permite ca un set <strong>de</strong> clase să se comporte ca un întreg, astfel ca evenimentele<br />

produse într-o clasă pot fi trimise către celelalte clase. Insă flexibilitatea acestui<br />

şablon are un preŃ, el <strong>de</strong>venind dificil <strong>de</strong> <strong>de</strong>zvoltat şi testat. Pe măsură ce lanŃul <strong>de</strong>vine<br />

mai complex, trebuie monitorizată cu atenŃie propagarea evenimentelor. Eşecul în<br />

trimiterea evenimentelor poate avea ca rezultat pier<strong>de</strong>rea mesajelor, acestea rămânând<br />

fără răspuns.<br />

Daca mai multe mesaje sunt produse într-o perioadă scurtă <strong>de</strong> timp, ele fiind<br />

apoi trimise <strong>de</strong> mai multe ori până sunt utilizate, are loc încetinirea sistemului.<br />

• Variante ale şablonului<br />

Exista mai multe căi <strong>de</strong> adaptare a şablonului Chain Of Responsibility încât el<br />

sa răspundă cerinŃelor diverselor aplicaŃii. Cele două strategii luate în consi<strong>de</strong>rare sunt<br />

cele <strong>de</strong> utilizare - handling - şi cele <strong>de</strong> trimitere mai <strong>de</strong>parte - forwarding - a<br />

mesajelor.<br />

La cele <strong>de</strong> utilizare important este modul în care a fost implementat handler-ul.<br />

Printre variantele acestor strategii se număra:<br />

- Default Handler - unele implementări pornesc <strong>de</strong> la un handler <strong>de</strong> bază.<br />

Acesta este <strong>de</strong> regulă folosit atunci când nu este <strong>de</strong>finită explicit o clasă care să<br />

trimită mesajul mai <strong>de</strong>parte. Este <strong>de</strong> mare ajutor în evitarea pier<strong>de</strong>rilor <strong>de</strong> mesaje<br />

- Handle And Extend - în cazul acestei variante, utilizarea evenimentelor<br />

implică adăugarea lor într-un comportament <strong>de</strong> bază pe măsura ce ele sunt propagate<br />

<strong>de</strong>-a lungul lanŃului. Acesta este <strong>de</strong> ajutor în activităŃile <strong>de</strong> logare<br />

- Dynamic Handler - unele implementări ale şablonului Chain Of<br />

Responsibility permit ca structura <strong>de</strong> trimitere a mesajelor să fie modificată la rulare.<br />

Prin <strong>de</strong>finirea unei meto<strong>de</strong> <strong>de</strong> setare pentru fiecare clasă a lanŃului, se poate <strong>de</strong>fini şi<br />

modifica lanŃul pe măsură ce este folosit în cadrul aplicaŃiei<br />

Strategiile <strong>de</strong> trimitere mai <strong>de</strong>parte a mesajelor <strong>de</strong>finesc modalităŃi <strong>de</strong> utilizare<br />

sau trimitere a mesajelor produse <strong>de</strong> o componentă:


- Handle By Default - utilizează orice mesaj care nu e trimis mai <strong>de</strong>parte în<br />

mod implicit<br />

- Propagate By Default - trimite mai <strong>de</strong>parte un mesaj care nu a fost utilizat<br />

implicit<br />

- Forward To Default Handler - mult mai complexă <strong>de</strong>cât şablonul <strong>de</strong> baza,<br />

aceasta abordare utilizează un handler implicit <strong>de</strong> mesaje. Orice mesaj care nu este<br />

utilizat la nivel <strong>de</strong> componentă sau care nu este trimis mei <strong>de</strong>parte către un alt handler,<br />

va fi trimis automat handler-ului implicit<br />

- Ignore By Default - orice mesaj care care nu e utilizat sau trimis mai <strong>de</strong>parte,<br />

este aruncat. Daca clasele din lanŃ produc evenimente care nu sunt folosite în<br />

aplicaŃie, această variantă este o metodă acceptabilă <strong>de</strong> a le elimina. Totuşi, ea trebuie<br />

utilizată cu atenŃie pentru a nu se elimina mesaje <strong>de</strong> care sistemul are nevoie<br />

• Şabloane asociate<br />

Printre şabloanele asociate se număra şablonul Composite. Şablonul<br />

Composite pune la dispoziŃie suport pentru o structură arborescentă şi pentru<br />

propagarea mesajelor iar Chain Of Responsibility conŃine reguli privind modul <strong>de</strong><br />

propagare. în plus, şablonul Composite tin<strong>de</strong> să trimită mesaje în jos - <strong>de</strong> la rădăcină<br />

către ramuri - în timp ce şablonul Chain Of Responsibility trimite <strong>de</strong> obicei mesaje în<br />

sus - <strong>de</strong> la ramuri către rădăcină.<br />

• Exemplu<br />

Se presupune că atunci când se cheltuiesc banii unei companii, trebuie cerută<br />

aprobarea şefului sau a şefului şefului:<br />

abstract class PurchasePcwer {<br />

pretecred final double base = 500; protected<br />

PurchasePower successor; public voia<br />

setSuccessor(PurchasePower successor){<br />

this.successor = successor; } abstract public<br />

void processRequest(PurchaseRequest<br />

requesr); i<br />

ciass Manager extenas PurchasePower {<br />

private final double ALLOWA3LE = 10 * base; public<br />

void processRequest(PurchaseRequest request ) {<br />

if(requesr.getAmount() < ALLOWABLE)<br />

System.out.println("Manager will<br />

approve Ş"+ request: . getAmount ());<br />

el.se if (successor != nuli)<br />

successor.processRequest(request);<br />

class Director extenas PurchasePower {<br />

private final double ALL0WA3LE = 20 * base; public void<br />

processRequest(PurchaseRequest request ) { if (request.<br />

getAmouni () < ALLOWABLE )<br />

System, out . println ( "Director will approve $"■+-<br />

request. gecAiriourit ( ) ) ;<br />

else if(successor !— nuli)<br />

successor.processRequest(request); }<br />

23


class PurcnaseKequest {<br />

privare irit r.unbei;<br />

private dcubie artiourit;<br />

private String purpose;<br />

public PurchaseRecuest ( i:vo runcer, dcubie amount, String<br />

puroose){<br />

this.num.ber = riun;cer;<br />

this . arr.ount -■ arnount;<br />

this.purpose = purpose;<br />

public aoubie getAmount { ) { return amounr.; } public void<br />

setAmount(double amt) { amourit = amt; } public String<br />

geiPurpose() { return purpose; } public void setPurpose(String<br />

reason) {purpose = reason;} public irit getNurr.ber () { return<br />

number; } public void setNumber (int nun;) { number = num; } }<br />

class CheckAuthority {<br />

public static void n;ain (String'] args) throws Exception{<br />

Manager manager = new Manager(); Director director =<br />

new Director(); manager.setSuccessor(director);<br />

while (true) {<br />

System.out.prinŃ In("IntroduceŃi suma:") ;<br />

System.out.prinŃ(">");<br />

double d = Double.parseDouble(new<br />

BufferedRea<strong>de</strong>r(new inputStreamRea<strong>de</strong>r<br />

(System.in)).readLine());<br />

manager.crocessRequest(new PurchaseRequest(0,<br />

d, "General"));<br />

III.2. Command<br />

• Cunoscut şi ca Action, Transaction<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: obiect<br />

Să învăluie o comandă într-un obiect astfel încât să poată fi stocată, trimisă<br />

către diferite meto<strong>de</strong> şi returnată ca oricare alt obiect.<br />

• Introducere<br />

Când un utilizator selectează o acŃiune ce urmeazc a fi executată, aplicaŃia<br />

trebuie să ştie <strong>de</strong> un<strong>de</strong> să extragă datele relevante şi comportamentul acestora. în mod<br />

normal, aplicaŃia ştie numărul opŃiunilor pe care le are un utilizator şi va reŃine acest<br />

lucru într-un loc central. Când o opŃiune e selectată, aplicaŃia află ce trebuie să facă,<br />

asamblează datele necesare şi apelează meto<strong>de</strong>le corespunzătoare.<br />

24


Multe din aplicaŃiile curente permit anularea fiecărei comenzi până la un<br />

anumit punct, cum ar fi ultima salvare efectuată. Daca se doreşte introducerea acestui<br />

lucru în aplicaŃia curentă, este nevoie <strong>de</strong> crearea unui istoric - o listă cu toate acŃiunile<br />

pe care utilizatorul le-a efectuat, cu toate datele utilizate şi cu starea prece<strong>de</strong>ntă. După<br />

vre-o trei sau patru acŃiuni, istoricul <strong>de</strong>vine mai mare <strong>de</strong>cât întreaga aplicaŃie şi asta<br />

din cauza redundanŃei datelor.<br />

Are mai mult sens combinarea acŃiunii utilizatorul într-un singur obiect -<br />

obiectul Command. Acesta conŃine datele necesare pentru o acŃiune specifică, precum<br />

şi comportamentul lor. Astfel, aplicaŃia doar invocă metoda <strong>de</strong> execuŃie a obiectului<br />

Command care execută comanda. AplicaŃia nu mai trebuie să cunoască toate opŃiunile<br />

disponibile şi poate fi uşor modificată încât să includă mai multe acŃiuni ale<br />

utilizatorului.<br />

• Utilizare<br />

Şablonul Command se foloseşte pentru:<br />

- anularea comenzilor, logare şi / sau tranzacŃii<br />

- executarea comenzilor în momente diferite<br />

• Descriere<br />

O aplicaŃie care nu foloseşte şablonul Command trebuie să conŃină meto<strong>de</strong><br />

care să se ocupe <strong>de</strong> fiecare eveniment care poate apărea. Prin urmare handler-ul<br />

trebuie să aibă toate informaŃiile pentru a putea executa acŃiunea. Introducerea unor<br />

noi acŃiuni necesită adăugarea <strong>de</strong> noi meto<strong>de</strong> clasei handler-ului.<br />

Şablonul Command încapsulează atât datele cât şi funcŃionalitatea necesară<br />

pentru a executa o acŃiune sau cerinŃă specifică. El pune la dispoziŃie o separare între<br />

cum trebuie executată o acŃiune şi momentul când trebuie executată. O aplicaŃie care<br />

foloseşte şablonul Command creează o sursă, un receptor şi o comandă. Comanda<br />

primeşte referinŃa către receptor şi sursa primeşte o referinŃă către comandă.<br />

Obiectul comandă este trimis către cel care 1-a invocat, care implementează<br />

interfaŃa Command. în forma ei cea mai simplă, interfaŃa are o metodă <strong>de</strong> executare.<br />

Clasele care o implementează reŃin receptorul ca o variabilă <strong>de</strong> instanŃă. Când metoda<br />

<strong>de</strong> executare e apelată, Command apelează metoda doAction din clasa Receiver.<br />

Command poate apela mai multe meto<strong>de</strong> ale clasei Receiver.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Command este următoarea:<br />

Invoker<br />

interface Command<br />

+void execulef)<br />

ConcreteCommand<br />

-Receiver target<br />

----<br />

►<br />

Receiver<br />

+void execute()<br />

+void action()<br />

25


Pentru implementarea şablonului Command este nevoie <strong>de</strong>:<br />

- Command - interfaŃa ce <strong>de</strong>fineşte meto<strong>de</strong>le pe care le foloseşte clasa Invoker<br />

- Invoker - clasa care apelează meto<strong>de</strong>le <strong>de</strong> executare ale obiectului Command<br />

- Receiver - Ńinta obiectului Command şi obiectul care în<strong>de</strong>plineşte cerinŃa<br />

- ConcreteCommand - clasa ce implementează interfaŃa Command<br />

Atunci când metoda <strong>de</strong> executare e apelată, clasa ConcreteCommand apelează<br />

una sau mai multe meto<strong>de</strong> ale clasei Receiver. Când se implementează şablonul<br />

Command, trebuie tăcute anumite alegeri privind utilizarea apelurilor. Se poate face<br />

unul din următoarele lucruri:<br />

- clasa care implementează interfaŃa Command se poate obŃine combinând<br />

clasele Invoker şi Receiver. trimiŃând astfel direct toate apelurile<br />

- clasa ConcreteCommand poate fi ia receptorul, rezolvând ea însăşi cerinŃele<br />

• Beneficii şi inconveniente<br />

Şablonul Command oferă flexibilitate în mai multe moduri:<br />

- <strong>de</strong>cuplarea sursei evenimentului <strong>de</strong> la obiectul care are cunoştinŃele necesare<br />

pentru a efectua sarcina<br />

- împărŃirea instanŃelor către Command între mai multe obiecte<br />

- permite înlocuirea comenzilor şi receptorilor la rulare<br />

- adăugarea uşoară <strong>de</strong> noi comenzi; se scrie o alta implementare a interfeŃei şi<br />

se adaugă aplicaŃiei<br />

• Variante ale şablonului<br />

Printre variantele şablonului Command se numără:<br />

- Undo - când se extin<strong>de</strong> interfaŃa Command cu o metodă <strong>de</strong> anularea a<br />

comenzii, povara implementării acestei meto<strong>de</strong> revine clasei care implementează<br />

interfaŃa<br />

Pentru a realiza anularea doar a ultimei comenzi, aplicaŃia trebuie să reŃină o<br />

referinŃă doar către ultima comandă. Când se execută o anulare, aplicaŃia apelează<br />

metoda <strong>de</strong> anulare doar a ultimei comenzi. Insă. utilizatorii pot să nu fie satisfăcuŃi<br />

doar cu anularea ultimei comenzi. Pentru a realiza anulări multiple, aplicaŃia trebuie<br />

să păstreze toate comenzile într-un istoric. Pentru a putea anula o comandă, interfaŃa<br />

Command trebuie să salveze toate informaŃiile necesare reparării unui obiect<br />

modificat. Aceste informaŃii includ receptorul şi orice argumente şi valori vechi.<br />

Receptorul trebuie schimbat astfel încât comanda să poată restaura valorile originale.<br />

Comenzile pot fi folosite <strong>de</strong> mai multe ori în contexte diferite. Prin urmare,<br />

comanda trebuie copiată înainte <strong>de</strong> a fi introdusă în istoric. Copierea comenzii previne<br />

erorile ce pot apărea în urma anulării şi executării repetate a ei. Mergând înapoi şi<br />

înainte în istoric nu ar trebui să fie o problemă, dar în cazul unei implementări<br />

incorecte, apar erori. Pentru a preveni asta. comanda ar trebui să reŃină câtă informaŃie<br />

este necesară pentru inversarea acŃiunii. Dacă o parte din informaŃii sunt stocate în<br />

receptor, şablonul Memento este cel mai indicat să reŃină starea receptorului.<br />

26


- MacroCommand - o macrocomandă este o colecŃie <strong>de</strong> alte comenzi.<br />

Macrocomenzile se pot crea folosind şablonul Composite. O macrocomandă conŃine o<br />

listă <strong>de</strong> subcomenzi. Când metoda <strong>de</strong> executare e apelată, macrocomandă trimite<br />

subcomenzi. Dacă macrocomandă suporta anulare, atunci toate comenzile interne<br />

trebuie să suporte anulări<br />

istoric<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Composite - folosit pentru implementarea macrocomenzilor<br />

- Memento - reŃine starea receptorului în ve<strong>de</strong>rea anularii unei comenzi<br />

- Prototype - poate fi folosit pentru a copia comanda înainte <strong>de</strong> a o plasa în<br />

- Singleton - în multe aplicaŃii, istoricul este implementat ca un Singleton<br />

• Exemplu<br />

Un exemplu al şablonului Command este următoarea clasă ce realizează<br />

începerea şi terminarea unei acŃiuni:<br />

class SubmitAction extends AbstractAction {<br />

private Component target;<br />

public SubmitAction (String name, Icon icon, Component: t){<br />

putValue(Action.NAME, name);<br />

putVaiue(Action.SMALL_ICON, icon);<br />

putValue(Action.SHORT_DESCRIPTION, name + " the<br />

program");<br />

target = t;<br />

public void actionPerformed(ActionEvent evt) {<br />

JOptionPane.showMessageDialog(target, "click pentru<br />

începere") ,-<br />

class ExitAction extends AbstractAction {<br />

private Component target;<br />

public ExitAction(String name, Icon icon, Component t){<br />

putValue(Action.NAME, name); putValue(Action.SMALL<br />

ICON, icon); putValue(Action.SHORT_DESCRIPTION,<br />

name + " the<br />

program"); target - t; } public<br />

void actionPerformed(ActionEvent evt) {<br />

int answer = JOptionPane.showConfirmDialog(target,<br />

"DoriŃi să ieşiŃi? ",<br />

"Confirmare", JOptionPane.YES_NO_OPTION); if<br />

(answer == JOptionPane.YES OPTION) {<br />

System.exit(0);<br />

27


III.3. Interpreter<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: clasă<br />

Să <strong>de</strong>finească un interpretor pentru un limbaj.<br />

• Introducere<br />

Cum se rezolvă un puzzle? O persoană înzestrată poate primi cele 5000 <strong>de</strong><br />

piese şi după nişte calcule, ştie un<strong>de</strong> trebuie plasată fiecare piesă. O altă modalitate<br />

este aceea <strong>de</strong> a alege piesele care aparŃin unei părŃi a puzzle-ului, încercând apoi<br />

rezolvarea părŃii mai mici. Se încearcă piesele până când doua dintre ele se potrivesc,<br />

repetându-se apoi proce<strong>de</strong>ul până când o parte mai mica e terminată. Se combină după<br />

aceea părŃile mai mici completându-se tot puzzle-ul.<br />

De multe ori rezolvarea unei probleme se face în acest mod. împărŃindu-se<br />

problema în subprobleme recursiv. Urmează apoi rezolvarea subproblemelor. Dar<br />

când problemele sunt inter<strong>de</strong>pen<strong>de</strong>nŃe, rezolvarea lor este dificilă.<br />

Cea mai bună soluŃie este crearea unui limbaj simplu care să mo<strong>de</strong>leze o<br />

problemă complexă şi să rezolve fraza ce o <strong>de</strong>scrie. Se poate simplifica astfel sarcina<br />

obŃinerii soluŃiei.<br />

• Utilizare<br />

Şablonul Interpreter se foloseşte când:<br />

- trebuie interpretat un limbaj simplu<br />

- probleme recursive pot fi exprimate în acel limbaj<br />

- eficienŃa nu este o problemă importantă<br />

• Descriere<br />

Şablonul Interpreter împarte o problemă în părŃi mai mici, apoi le reuneşte<br />

într-o frază aparŃinând unui limbaj simplu. Se interpretează apoi fraza şi se rezolvă<br />

problema pas cu pas. Acest lucru se face creând un arbore <strong>de</strong> sintaxă abstract.<br />

O exemplu matematic simplu este: rezultat = (a + b) / c; rezultatul <strong>de</strong>pin<strong>de</strong> <strong>de</strong><br />

valorile lui a, b şi c. Presupunând că valorile sunt 4, 2 şi 3. rezultatul va fi 2. Cum se<br />

ştie acest lucru? Mai întâi, i se asociază mental lui a valoarea 4. lui b 2 şi lui c 3. Apoi<br />

se adună a cu b, rezultând valoarea 6 care se împarte apoi la c. Rezolvând problema<br />

cu şablonul Interpreter, se parcurge un set <strong>de</strong> paşi similar. Fiecare din variabile este un<br />

operand, la fel cum sunt şi valorile intermediare. Regulile gramaticale (+ pentru<br />

adunare şi / pentru împărŃire) sunt operaŃii sau operatori. Fiecare regulă gramaticală<br />

este implementată într-o clasă separată şi fiecare valoare din dreapta regulii <strong>de</strong>vine o<br />

variabilă instanŃă.<br />

28


• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Interpretei" este următoarea:<br />

Client<br />

Context<br />

Şablonul Interpretei" necesită:<br />

interface Exprcssion<br />

+void interpreUContext c)<br />

TerminalExpression NonterminalExpression<br />

+void interpret(Context c) +void interpret(Context c)<br />

- Expression - interfaŃa prin intermediul căreia utilizatorul interacŃionează cu<br />

expresiile<br />

- TerminalExpression - clasa care implementează interfaŃa Expression,<br />

utilizată pentru nodurile terminale ale arborelui <strong>de</strong> sintaxă<br />

- NonterminalExpression - cealaltă implementare a interfeŃei Expression.<br />

utilizată pentru nodurile neterminale ale arborelui <strong>de</strong> sintaxă. ConŃine o referinŃă către<br />

următoarea expresie şi apelează metoda <strong>de</strong> interpretare pentru fiecare dintre copiii săi<br />

- Context - conŃine informaŃiile necesare în mai multe locuri ale<br />

interpretorului. Serveşte drept un canal <strong>de</strong> comunicare între instanŃele mai multor<br />

expresii<br />

- Client - construieşte sau primeşte o instanŃă a unui arbore <strong>de</strong> sintaxă abstract.<br />

Acest arbore <strong>de</strong> sintaxă este compus din instanŃe ale obiectelor <strong>de</strong> tip<br />

TerminalExpressions şi NonterminalExpressions<br />

• Beneficii şi inconveniente<br />

Şablonul Interpreter poate fi uşor modificat pentru a reflecta schimbările<br />

produse în gramatică. Pentru adăugarea unei noi reguli se creează o altă clasă care<br />

implementează interfaŃa Expression. O regulă se poate modifica uşor prin extin<strong>de</strong>rea<br />

clasei vechi şi suprascrierea meto<strong>de</strong>i <strong>de</strong> interpretare.<br />

Şablonul Interpreter nu este potrivit atunci când gramatica este mare. El poate<br />

conduce la un număr mare <strong>de</strong> clase în cazul în care limbajul conŃine multe reguli.<br />

Fiecare regulă adăugata limbajului necesită crearea unei noi clase în interpretor. Acest<br />

lucru poate duce în final la probleme <strong>de</strong> testare şi mentenanŃă.<br />

Se pot adăuga meto<strong>de</strong> interfeŃei Expression pentru a mari funcŃionalitatea<br />

expresiilor. Pentru o mai mare flexibilitate, se foloseşte şablonul Visitor care permite<br />

schimbarea dinamică a meto<strong>de</strong>i <strong>de</strong> interpretare.<br />

29


Crearea arborelui <strong>de</strong> sintaxă abstract poate pune probleme, el nefiind <strong>de</strong>finit <strong>de</strong><br />

şablonul Interpreter. Acesta presupune că arborele a fost creat altun<strong>de</strong>va.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Composite - structura pentru interpretarea expresiilor se bazează pe şablonul<br />

Composite, folosind expresii terminale şi neterminale<br />

- Flyweight - pentru reducerea numărului <strong>de</strong> obiecte redundante sau similare<br />

- Iterator - pentru iterarea în cadrul arborelui <strong>de</strong> sintaxă abstract şi a nodurilor<br />

sale<br />

- Visitor - prin folosirea acestui şablon. Interpreter câştigă flexibilitate<br />

• Exemplu<br />

Consi<strong>de</strong>rând o expresie dată. cu ajutorul şablonului Interpreter se poate filtra<br />

informaŃia care se doreşte:<br />

public void myParser() {<br />

StringTokenizer hol<strong>de</strong>r = new StringTokenizer<br />

(expression, token); String[]<br />

toBeMatched = r.ew Strir.g<br />

[hol<strong>de</strong>r.countTokens()];<br />

int idx == 0;<br />

while(hol<strong>de</strong>r.hasMoreTokens () ) {<br />

String item = hol<strong>de</strong>r.nextToken(); int start =<br />

item.in<strong>de</strong>xOf(","); if (start=--C) { iten = item.<br />

substring ( 2 ) ; } toBeMatched[idx] = item; idx +4;<br />

}<br />

result = Arrays.asList(toBeMatched); }<br />

public List getParseResult() { return result; }<br />

public void interpret() {<br />

StringBuffer buffer = new StringBuffer();<br />

Listlterator iist = result.listlterator();<br />

while(Iist.hasNext()){<br />

Stri.ng tcken = (String)1 ist.next(); if<br />

(token.equais("SFO")) {<br />

token = "San Francisco";<br />

}else if(token.equais("CA")) {<br />

token = "Canada"; }<br />

buffer.append(" " ^ token); }<br />

interpreted = buffer.toString();<br />

}<br />

public String getInterpretedResult() {<br />

return interoreted;<br />

30


III.4. Iterator<br />

• Cunoscut şi ca Cursor<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental -<br />

Nivel: componentă<br />

Să pună la dispoziŃie o cale <strong>de</strong> acces secvenŃial la articolele dintr-o colecŃie<br />

care este in<strong>de</strong>pen<strong>de</strong>ntă sau separată <strong>de</strong> colecŃia <strong>de</strong> bază.<br />

• Introducere<br />

Managerul personal <strong>de</strong> informaŃii utilizează multe colecŃii <strong>de</strong> vreme ce Ńine<br />

evi<strong>de</strong>nŃa unei cantităŃi mari <strong>de</strong> date. Adrese, contacte, proiecte, întâlniri, notiŃe, liste<br />

cu lucruri ce trebuie făcute - toate aceste presupun abilitatea <strong>de</strong> a se reŃine grupuri <strong>de</strong><br />

obiecte legate între ele. Pentru a se putea salva toate aceste tipuri <strong>de</strong> informaŃii, se pot<br />

crea clase care sa reŃină fiecare grup <strong>de</strong> articole în parte. în acest fel. se pot <strong>de</strong>zvolta<br />

colecŃii care să în<strong>de</strong>plinească nevoile specifice fiecărui grup <strong>de</strong> obiecte.<br />

Apare însă o problemă atunci când se doreşte parcurgerea fiecărei colecŃii.<br />

Dacă se creează clase care să în<strong>de</strong>plinească nevoile obiectelor stocate, nu există nici o<br />

garanŃie că elementele pot fi retrase şi folosite într-o modalitate uniformă. Întâlnirile<br />

pot fi organizate în subgrupuri în funcŃie <strong>de</strong> date. în timp ce contactele pot fi stocate<br />

alfabetic iar notiŃele pot fi ordonate secvenŃial.<br />

Acest lucru conduce la scrierea <strong>de</strong> cod specific fiecărei colecŃii în parte pentru<br />

a se putea naviga printre articolele fiecărui grup. precum şi copierea codului respectiv<br />

în fiecare parte a sistemului un<strong>de</strong> se foloseşte un grup. Rezultă un cod foarte<br />

complicat şi greu <strong>de</strong> întreŃinut. Mai mult. trebuie cunoscute fiecare tipuri <strong>de</strong> colecŃii<br />

folosite în <strong>de</strong>taliu pentru a menŃine obiectele în managerul personal.<br />

Şablonul Iterator rezolvă aceste probleme prin <strong>de</strong>finirea unei interfeŃe<br />

uniforme pentru parcurgerea oricărei colecŃii. Când se folosesc iteratori în sistem, se<br />

pot utiliza aceleaşi meto<strong>de</strong> <strong>de</strong> apel atunci când se navighează printr-o listă <strong>de</strong><br />

contacte, precum şi atunci când se printează o listă cu lucrurile ce trebuie făcute.<br />

• Utilizare<br />

Şablonul Iterator se foloseşte pentru:<br />

- a pune la dispoziŃie o cale uniformă şi consistentă <strong>de</strong> a parcurge elementele<br />

unei colecŃii care nu este legată <strong>de</strong> implementarea colecŃiei<br />

- a permite parcurgerea colecŃiilor multiple, lăsând mai mulŃi clienŃi să<br />

navigheze simultan în cadrul aceleaşi colecŃii <strong>de</strong> bază


■ Descriere<br />

Şablonul Iterator permite standardizarea şi simplificarea codului ce trebuie<br />

scris pentru parcurgerea unei colecŃii. Clasele ce implementează colecŃiile tind să fie<br />

create pe baza a ceea ce se stochează şi nu pe baza cerinŃelor <strong>de</strong> parcurgere. Avantajul<br />

oferit <strong>de</strong> Iterator este acela că prezintă o cale consistentă <strong>de</strong> a naviga în cadrul<br />

colecŃiilor indiferent <strong>de</strong> structura <strong>de</strong> bază.<br />

Un Iterator în Java foloseşte <strong>de</strong> regulă o interfaŃă care <strong>de</strong>fineşte operaŃiile lui<br />

principale, punând apoi la dispoziŃie una sau mai multe implementări care fac legătura<br />

cu colecŃia <strong>de</strong> bază. OperaŃiile fundamentale ale Iterator-ului sunt:<br />

- First<br />

-Next<br />

- IsDone<br />

- Currentltem<br />

Aceste operaŃii <strong>de</strong>finesc serviciile <strong>de</strong> bază pe care un Iterator le oferă. în<br />

termeni mai generali, un Iterator ar trebui să ofere următoarele capacităŃi:<br />

- Navigation - mişcarea în faŃă şi în spate în cadrul colecŃiei<br />

- Retrieval - obŃinerea elementului curent la care se face referinŃă<br />

- Validation - <strong>de</strong>ci<strong>de</strong>rea dacă mai sunt elemente în colecŃie, Ńinându-se cont <strong>de</strong><br />

poziŃia curentă a Iterator-ului<br />

Iteratorii pot conŃine şi operaŃii extinse, cum ar fi meto<strong>de</strong> <strong>de</strong> mişcare către<br />

primul sau ultimul element al colecŃiei.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Iterator este următoarea:<br />

interface Iterator<br />

+Object fir st ()<br />

+ Objecl nexJf)<br />

+boolean hasMoreElement'()<br />

+Object getCurrentElement'()<br />

Concretelterator<br />

+Object first()<br />

+Object next()<br />

+boolean hasMoreElement()<br />

+Object getCurrentElement()<br />

interface Aggregate<br />

+Iterator gel'Iterator•()<br />

ConereteAggregate<br />

+Iterator getlteratorQ<br />

return new ConcretelteratorQ<br />

32


Pentru implementarea şablonului Iterator este nevoie <strong>de</strong>:<br />

- Iterator - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le standard ale Iterator-ului. Minim,<br />

ea trebuie să conŃină meto<strong>de</strong> pentru parcurgerea, obŃinerea şi validarea elementelor<br />

(first, next, hasMoreElements şi getCurrentltem)<br />

- Concretelterator - clase care implementează interfaŃa Iterator. Aceste clase<br />

conŃin o referinŃă către colecŃia <strong>de</strong> bază. în mod normal, instanŃele sunt create <strong>de</strong> clasa<br />

ConcreteAggregate. Deoarece există o strânsa legătură între ConcreteAggregate şi<br />

Concretelterator, aceasta din urmă face <strong>de</strong> obicei parte din prima<br />

- Aggregate - interfaŃa ce <strong>de</strong>fineşte o metodă pentru producerea Iterator-ului<br />

- ConcreteAggregate - clasa ce implementează interfaŃa Aggregate, construind<br />

la comanda un obiect <strong>de</strong> tip Concretelterator. Ea execută acŃiuni în funcŃie <strong>de</strong><br />

responsabilitatea fundamentală a sa <strong>de</strong> reprezentare a colecŃiilor <strong>de</strong> obiecte din sistem<br />

• Beneficii şi inconveniente<br />

Multe din beneficiile şablonului Iterator sunt date <strong>de</strong> avantajele <strong>de</strong>finirii unei<br />

interfeŃe uniforme pentru parcurgerea colecŃiilor. Se simplifică astfel consi<strong>de</strong>rabil<br />

utilizarea colecŃiilor şi se permite folosirea polimorfismului în lucrul cu colecŃiile.<br />

Pentru printarea elementelor dintr-o colecŃie, <strong>de</strong> exemplu, se poate folosi un Iterator,<br />

apelându-se metoda toString pentru orice obiect, indiferent <strong>de</strong> colecŃia <strong>de</strong> bază.<br />

în plus, Iteratorii permit clienŃilor navigarea multiplă în cadrul aceleiaşi<br />

colecŃii. Iterator-ul poate fi privit ca un cursor în interiorul colecŃiei.<br />

Un inconvenient al acestui şablon este acela că oferă iluzia <strong>de</strong> ordine în<br />

structurile neordonate. De exemplu, pentru un set ce nu suportă ordonare, Iterator-ul<br />

va pune la dispoziŃie elementele într-o secvenŃă arbitrară care se poate schimba <strong>de</strong>-a<br />

lungul timpului. Dacă nu se observă acest lucru, se poate scrie un cod pentru<br />

asigurarea consistenŃei în structura <strong>de</strong> bază, apărând astfel probleme.<br />

• Variante ale şablonului<br />

Şablonul Iterator prezintă mai multe posibilităŃi <strong>de</strong> implementare. Obiectele <strong>de</strong><br />

tip Concretelterator pot fi interne sau externe. Iteratorii externi au meto<strong>de</strong> specifice<br />

pentru navigarea în cadrul colecŃiei, în timp ce Iteratorii interni permit navigarea în<br />

ciclu printre elemente.<br />

Obiectele <strong>de</strong> tip Concretelterator pot fi dinamice sau statice. Un obiect<br />

dinamic face o referire directă către colecŃia <strong>de</strong> bază, <strong>de</strong>ci va reflecta mereu starea<br />

acesteia. Pe <strong>de</strong> alta parte, un obiect static creează un instantaneu al colecŃiei,<br />

referindu-se la această copie pe durata utilizării.<br />

Iteratorii nuli pot fi <strong>de</strong>finiŃi pentru parcurgerea structurilor complexe, cum ar fi<br />

arborii. Folosind un iterator ce reprezintă un "nod final", este posibilă scrierea unui<br />

cod recursiv simplu pentru vizitarea tuturor nodurilor arborelui.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Factory Method - clasele ce implementează colecŃiile conŃin <strong>de</strong> regulă o<br />

metodă <strong>de</strong> producere a Iterator-ului<br />

33


- Visitor - atunci când şablonul Yisitor este folosit pentru un grup <strong>de</strong> obiecte,<br />

un Itcrator este <strong>de</strong> asemenea folosit pentru parcurgerea în ciclu a elementelor<br />

- Value List Handler - acest şablon se bazează pe Iterator în sensul că permite<br />

clientului să sară peste o colecŃie<br />

• Exemplu<br />

Avem interfaŃa Emplovee şi clasele Manager şi Worker care o implementează.<br />

Clasa EmployeeTcst va crea o listă şi va folosi un iterator pentru a o parcurge:<br />

interface Employee { public abstracr. double earr.ings ( ) ; )<br />

class Manager inpîements Err.ployee { private dcuble<br />

weeklySalary; private String name; public Manager (String<br />

narne, double s) {<br />

this.nane = name; setWeeklySalary ( s) ;<br />

} void setWeeklySalary(double s) {<br />

if (s > 0) { weeklySalary = s; }<br />

else weeklySalary = 0;<br />

}<br />

public double earnings() { return weeklySaiary; }<br />

public String get Name () { return narr.e; }<br />

public Strinq toStringO {return "Manager:" + getName();}<br />

}<br />

class Worker impienents Employee { private doubie<br />

wagePerPiece; private int quantity; private<br />

String name; public Worker (Strmg narne, douoi e<br />

w, mt q) {<br />

this.name = name;<br />

setWagePerPiece Ńw) ;<br />

setQuantity(q);<br />

i<br />

void setWagePerPiece(double w) {<br />

if (w > 0) wagePerPiece = w;<br />

else wagePerPiece = 0;<br />

}<br />

void setQuantity(int q) {<br />

if ( q > 0) quantity = q; else<br />

quantity = 0; }<br />

public String getName() { return name; }<br />

public double earnings() {return quantity*wagePerPiece;} public<br />

String toString() {return "Worker:" + getName(); } ) class<br />

EmployeeTest {<br />

public static void main(String[] args) {<br />

iava.util.List list = new ArrayList();<br />

list.add(new Manager("Bill", 800.00));<br />

list.add(new Worker("Al", 2.5, 200));<br />

list.add{new Manager("Peter", 1200.00));<br />

list.add(new Worker("Mark", 4.5, 333));<br />

Iterator iterator = list.iterator();<br />

while(iterator.hasNext()) {<br />

Employee em == (Employee ) iterator . next ();<br />

System.out.prinŃ(ei + " câştigă $"); System,<br />

out .println (ora. earnings ( ) } ;<br />

34


III.5. Mediator<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: componentă<br />

Să simplifice comunicarea între obiectele unui sistem prin introducerea unui<br />

singur obiect care să se ocupe <strong>de</strong> transmiterea mesajelor între celelalte.<br />

• Introducere<br />

O caracteristică folositoare a managerului personal <strong>de</strong> informaŃii este aceea <strong>de</strong><br />

distribuire a informaŃiilor între mai mulŃi utilizatori, astfel încât cineva să poată aranja<br />

o întâlnire la care un alt utilizator să participe. în acest fel, toŃi participanŃii vor fi<br />

ŃinuŃi la curent cu planurile <strong>de</strong> întâlniri.<br />

Cum se pot însă administra întâlnirile, presupunând că mai multe managere <strong>de</strong><br />

informaŃii rulează? O modalitate este <strong>de</strong> a da fiecăruia o copie a unui obiect <strong>de</strong> tip<br />

Appointment, asigurându-se că ele au acces local la date. Apare o problemă: cum se<br />

menŃine informaŃia consistentă între toŃi utilizatorii? De exemplu, dacă un utilizator<br />

creează o întâlnire iar mai târziu îi schimbă data. cum află ceilalŃi participanŃi la<br />

întâlnire acest lucru? Se poate face aplicaŃia utilizatorului responsabilă şi cu<br />

administrarea modificărilor, Totuşi, dacă unuia dintre participanŃii la întâlnire i se<br />

permite să facă modificări, asta înseamnă că fiecare manager <strong>de</strong> informaŃii trebuie să<br />

urmărească activitatea celorlalte managere. Administrarea comunicării între un număr<br />

mare <strong>de</strong> participanŃi <strong>de</strong>vine foarte dificilă. în cel mai bun caz, este ineficient şi<br />

costisitor în ceea ce priveşte reŃeaua: în cel mai rău caz. planificarea unei întâlniri se<br />

transformă în haos.<br />

Având în ve<strong>de</strong>re posibila complexitate a sistemului, este preferabilă<br />

trimiterea/primirea cerinŃelor către/<strong>de</strong> la un obiect central care să ia <strong>de</strong>cizii privind<br />

meto<strong>de</strong>le <strong>de</strong> apelare. Aceasta este esenŃa şablonului Mediator. în loc <strong>de</strong> a face<br />

obiectul <strong>de</strong> tip Appointment responsabil <strong>de</strong> trimiterea modificărilor, se creează un<br />

obiect AppointmenfMediator. De fiecare dată când obiectul Appointment se modifică,<br />

se apelează o metoda a Mediator-ului care poate <strong>de</strong>ci<strong>de</strong> apelarea unor meto<strong>de</strong> pentru a<br />

confirma modificările. în funcŃie <strong>de</strong> rezultat, obiectul AppointmentManager transmite<br />

mesajul original sau o versiune revizuită a lui care conŃine datele privind modificarea<br />

orei întâlnirii sau anularea acesteia.<br />

Utilizare<br />

Şablonul Mediator se foloseşte când:<br />

- există reguli complexe ale comunicării între obiectele sistemului<br />

- se doreşte ca obiectele să fie păstrate simple şi uşor <strong>de</strong> administrat<br />

35


• Descriere<br />

Pe măsură ce comunicarea între obiectele unei aplicaŃii <strong>de</strong>vine din ce în ce mai<br />

complexă, administrarea acesteia este mult mai dificilă. Manipularea evenimentelor<br />

pentru controlul unei simple foi <strong>de</strong> calcul tabelar poate implica scrierea unui cod<br />

pentru fiecare componentă reŃea. Totuşi, dacă interfaŃa grafică cu utilizatorul este<br />

estinsă pentru a inclu<strong>de</strong> o reŃea, un grafic şi pentru a înregistra câmpurile afişate, ea<br />

<strong>de</strong>vine mult mai dificilă în ceea ce priveşte administrarea codului. O schimbarea a<br />

uneia dintre componente poate produce modificări în alte componente.<br />

Şablonul Mediator permite rezolvarea acestei probleme, <strong>de</strong>finind o clasă a<br />

cărei responsabilităŃi este comunicarea în general. Se simplifică mult celelalte clase<br />

ale sistemului, nemaifiind necesară administrarea comunicărilor propriu-zise.<br />

Obiectul mediator are rolul unui drum al sistemului, centralizând logica privind<br />

trimiterea şi primirea mesajelor. Componentele trimit mesaje către mediator şi se<br />

bazează pe acestea să le trimită notificări ale modificărilor apărute. Implementarea<br />

Mediator-ului se face atunci când interfaŃa grafică cu utilizatorul trebuie să se<br />

comporte ca un întreg.<br />

Pentru a ilustra utilitatea reală a şablonului Mediator, se pot consi<strong>de</strong>ra<br />

conferinŃele telefonice. Multe companii <strong>de</strong> telefonic oferă teleconferinŃe iar interfaŃa<br />

<strong>de</strong> comutare a interlocutorilor este un fel <strong>de</strong> mediator. Ea permite transmiterea<br />

mesajelor între indivizii care participa la conferinŃa.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Mediator este următoarea:<br />

interface Mediator interface Client<br />

+void broadcastEventf)<br />

+void broadcastEventQ<br />

-Client[] clients<br />

ConcreteMediator<br />

pentru toŃi clienŃii c c.handleEventQ<br />

Implementarea şablonului Mediator necesită:<br />

+void handleEventf)<br />

+void<br />

broadcastEventf)<br />

+void<br />

ConcreteClient<br />

-Mediator mediator<br />

handleEventQ +void<br />

broadcastEventQ<br />

med iator.broadcastEvent()<br />

- Mediator - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le pe care clienŃii le pot apela<br />

36


- ConcrcteMediator - clasa care implementează interfaŃa Mediator. Această<br />

clasă reprezintă un mediator între mai multe clase <strong>de</strong> clienŃi. ConŃine informaŃiile<br />

<strong>de</strong>spre procese, precum şi referinŃe către clienŃii săi. Pe baza informaŃiilor pe care le<br />

primeşte Mediator-ul, ea poate fie invoca meto<strong>de</strong>le specifice, fie o metodă generică<br />

pentru a informa clienŃii <strong>de</strong> modificările survenite, fie o combinaŃie a acestora<br />

- Client - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le generale pe care un Mediator le<br />

poate folosi pentru a crea instanŃe ale clienŃilor<br />

- ConcreteClient - clasa care implementează interfaŃa Client şi toate meto<strong>de</strong>le<br />

client. Ha poate păstra o referinŃă către o instanŃă Mediator pentru a informa clienŃii<br />

când apare o schimbare<br />

• Beneficii şi inconveniente<br />

Componentele individuale <strong>de</strong>vin mai simple şi mai uşor <strong>de</strong> utilizat, <strong>de</strong>oarece<br />

ele nu mai sunt nevoite sa trimită mesaje direct între ele. Strategiile <strong>de</strong> comunicarea<br />

generală <strong>de</strong>vin mai uşor <strong>de</strong> administrat, ele fiind acum responsabilitatea exclusivă a<br />

mediator-ului. Clasele unei aplicaŃii pot fi folosite şi în cadrul aplicaŃiei, fiind<br />

necesară doar rescrierea Mediator-ului pentru noua aplicaŃie.<br />

Testarea unor implementări complexe ale unui Mediator poate fi <strong>de</strong>stul <strong>de</strong><br />

dificilă, <strong>de</strong>oarece trebuie testată o componentă care constă din Mediator şi obiectele<br />

asociate lui. Codul Mediator-ului poate <strong>de</strong>veni greu <strong>de</strong> administrat pe măsura ce<br />

numărul şi complexitatea participanŃilor creşte. O posibilă soluŃie este <strong>de</strong> a transforma<br />

mediatorul într-o structură compusă, bazată pe un număr <strong>de</strong> mediatori foarte<br />

focalizaŃi. în acest caz. Mediator-ul e format dintr-un obiect central <strong>de</strong> administrare<br />

asociat unui număr <strong>de</strong> clase individuale, fiecare punând la dispoziŃie o parte <strong>de</strong><br />

funcŃionalitate.<br />

■ Variante ale şablonului<br />

- UnidirecŃional Communication - unele implementări permit doar trimiterea<br />

sau doar primirea <strong>de</strong> clienŃi în sistem<br />

- Threading - ca multe alte şabloane comportamentale. Mediator-ul foloseşte<br />

lucrul cu multiple fire <strong>de</strong> execuŃie<br />

- Configurable Roles - în această variantă, clientul <strong>de</strong>fineşte un rol, care se<br />

poate modifica pe măsură ce sistemul rulează, rol ce <strong>de</strong>fineşte cerinŃele trimiterii <strong>de</strong><br />

mesaje. Deja cu o implementare complexă, <strong>de</strong>finirea participanŃilor ca roluri poate<br />

conduce la un Mediator mai generic<br />

- Client Puii - un Mediator poate stoca mesaje <strong>de</strong>taliate şi trimite doar o<br />

notificare generală către clienŃi. ClienŃii pot cere apoi informaŃii <strong>de</strong>taliate <strong>de</strong>spre un<br />

eveniment dacă este cazul<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Observer - acest şablon este <strong>de</strong> obicei folosit pentru a administra<br />

comunicarea dintre Client şi Mediator, atunci când aceasta este locală<br />

- Half-Object Plus Protocol - şablonul Mediator ce rulează <strong>de</strong>-a lungul unei<br />

reŃele poate folosi şablonul Half-Object Plus Protocol care conŃine suport pentru<br />

comunicare<br />

37


Exemplu<br />

Având o interfaŃă grafică complexă, <strong>de</strong> fiecare dată când se apasă pe un buton<br />

o acŃiune este pornită sau oprită. Se poate <strong>de</strong>scrie o clasă Mediator care să conŃină<br />

toate clasele asociate:<br />

class Mediator {<br />

BtnView btnView;<br />

BtnSearch btnSearch;<br />

Btr.Book btnBook;<br />

LbIDisplay show;;<br />

void registerView (5tr.Vi.ew v) { btnView = v; }<br />

void registerSearch(BtnSearch s) { btnSearch = s; }<br />

void registerBook(BtnBook b) { btnBook = b; }<br />

void registerDisplay(LbIDisplay d) { show = d; }<br />

veid book() {<br />

btnBooK.setEnabled(false);<br />

btnView.setEnabled(true);<br />

btnSearch.setEnabled(true);<br />

show.setText("booking...");<br />

btnView.setEnabled(false);<br />

btnSearch.setEnabled (true) ;<br />

btnBook.setEnabled(true);<br />

void search() {<br />

btnSearch.setEnabled ( false);<br />

btnView.setEnabled(true);<br />

btnBook.setEnabled(true);<br />

show.setText("searching...");<br />

III.6. Memento<br />

• Cunoscut şi ca Token, Snapshot<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: obiect<br />

Să păstreze un instantaneu al stării unui obiect, astfel încât obiectul să poate<br />

reveni la starea originală fără a-şi <strong>de</strong>zvălui conŃinutul restului lumii.<br />

• Introducere<br />

Fiecare aplicaŃie are obiecte ale căror informaŃii trebuie păstrate şi după<br />

terminarea duratei <strong>de</strong> viaŃă a obiectelor. De regulă, acest lucru se face prin distribuirea<br />

datelor, dar dacă informaŃiile private ale unei obiect trebuie păstrate? Trimiterea <strong>de</strong><br />

date către un alt obiect este o i<strong>de</strong>e rea. încălcând principiul încapsulării. Dacă se trimit<br />

date către alte obiecte, acestea pot citi sau, mai rău. pot modifica datele.<br />

38


Este asemănător cu mersul la un parc naŃional un<strong>de</strong> se protejează elanul.<br />

Obiectul ale cărui date sunt salvate este elanul. Xu este permisă luarea acasă a<br />

elanului, dar ve<strong>de</strong>ri şi tricouri cu elanul sunt disponibile la magazinul <strong>de</strong> suveniruri al<br />

parcului.<br />

O mai bună abordare este folosirea unui obiect care să conŃină datele ce<br />

trebuie salvate. Se trimite acest obiect care poate fi folosit pentru recrearea<br />

originalului, în loc <strong>de</strong> a trimite datele neprelucrate. Alte obiecte nu ar putea citi sau<br />

modifica datele <strong>de</strong>oarece acestea ar fi încapsulate. Acesta este şablonul Memento,<br />

un<strong>de</strong> un obiect este folosit ca un suvenir cu ajutorul căruia se poate restabili starea<br />

originală a obiectului iniŃial.<br />

• Utilizare<br />

Şablonul Memento se foloseşte când:<br />

- este nevoie reŃinerea unui instantaneu al stării obiectului<br />

- acest instantaneu e utilizat pentru recrearea stării originale a obiectului<br />

- o interfaŃă directă către obiect încalcă încapsularea<br />

• Descriere<br />

Dacă încapsularea a fost implementată corect, atunci toate obiectele au stări<br />

private şi vor permite acces la atribute doar prin meto<strong>de</strong>. Dar poate fi necesară<br />

trimiterea stării curente către un alt obiect, <strong>de</strong> exemplu, în ve<strong>de</strong>rea restaurării stării<br />

iniŃiale într-un moment ulterior. O posibilitate <strong>de</strong> a face asta este <strong>de</strong> a trimite starea<br />

direct către obiectul interesat. Apar însă inconveniente, cum ar fi expunerea structurii<br />

interne a obiectului sau posibilitatea modificării stării obiectului <strong>de</strong> către un altul.<br />

SoluŃia este învăluirea stării care se doreşte păstrată într-un alt obiect folosind<br />

şablonul Memento. Memento este un obiect care conŃine starea internă curentă a<br />

obiectului original <strong>de</strong> tip Originator. doar acesta din urma putând accesa şi retrage<br />

informaŃii din Memento. Pentru restul lumii, Memento reprezintă doar un obiect<br />

arbitrar.<br />

■ Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Memento este următoarea:<br />

Originator<br />

-State state<br />

+void setMemento(Memento m)<br />

+Object getMemento()<br />

1 creează<br />

t<br />

Memento<br />

StateHol<strong>de</strong>r<br />

-State state Memento este o clasa statica<br />

interna a Originator-ului<br />

+State getState() +void<br />

setState(State s)<br />

39


Pentru implementarea şablonului Memento este nevoie <strong>de</strong>:<br />

- Originator - creează Memento, lblosindu-1 ulterior pentru a-şi restaura starea<br />

- Memento - clasa statică a Originator-ului şi păstrătorul stării acestuia.<br />

Originator-ul <strong>de</strong>termină câte date sunt păstrate <strong>de</strong> Memento. Starea reŃinută <strong>de</strong><br />

Memento trebuie să fie inaccesibilă tuturor, cu excepŃia Originator-ului<br />

- StateHol<strong>de</strong>r - obiectul care doreşte să păstreze starea. El nu trebuie să ştie ce<br />

se afla în interiorul obiectului Memento: trebuie doar să ştie că obiectul pe care-1<br />

primeşte îi permite să restaureze starea Originator-ului<br />

Deoarece Memento trebuie să fie accesibil doar Originator-ului, este preferabil<br />

ca Memento să fie o clasă publică din interiorul Originator-ului. Toate meto<strong>de</strong>le sunt<br />

<strong>de</strong>clarate private astfel că sunt disponibile doar Memento-ului şi clasei care-1 conŃine.<br />

InstanŃe ale unei clase interne sunt mereu asociate cu cele are clasei externe. Acest<br />

lucru este necesar <strong>de</strong>oarece o clasă internă are întot<strong>de</strong>auna acces la instanŃe ale<br />

variabilelor clasei externe. Acest lucru cauzează însă o problemă în această situaŃie.<br />

Memento ar trebui să fie in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> o instanŃă specifică a Originator-ului. Prin<br />

urmare clasa Memento trebuie să fie statică.<br />

■ Beneficii şi inconveniente<br />

Folosirea şablonului Memento are următoarele consecinŃe:<br />

- respectă principiul încapsulării - chiar şi când starea Originator-ului trebuie<br />

să fie stocată în afara obiectului <strong>de</strong> tip Originator într-un client, starea este<br />

inaccesibilă clientului. Are doar o referinŃă către obiectul Memento, neexistând nici o<br />

cale <strong>de</strong> a accesa informaŃia din interior. Totodată face treaba clientul mai simplă<br />

<strong>de</strong>oarece el nu mai trebuie să ştie totul <strong>de</strong>spre lucrul intern al Originator-ului,<br />

exceptând modul <strong>de</strong> obŃinere şi <strong>de</strong> utilizare a Memento-ului<br />

- un Originator simplu - presupunând că Originator-ul trebuie să urmărească<br />

toate stările, el va <strong>de</strong>veni curând plin şi greu <strong>de</strong> mânuit. Este mult mai uşor dacă se dă<br />

această responsabilitate clientului. Originator-ul trebuie acum doar să fie capabil să<br />

creeze şi să utilizeze Memento-ul<br />

- Memento-uri costisitoare - Memento-urile sunt costisitor <strong>de</strong> creat daca<br />

fiecare bucată a stării Originator-ului trebuie stocată în Memento. Daca Originator-ul<br />

este mare. şablonul Memento nu este unul potrivit<br />

- stocare costisitoare a Memento-ului - obiectul care păstrează starea este<br />

responsabil cu administrarea ciclului <strong>de</strong> viaŃă după ce primeşte Memento-ul <strong>de</strong> la<br />

Originator. Totuşi, el nu ştie cât <strong>de</strong> mare este Memento-ul <strong>de</strong> fapt. Daca el nu este<br />

păstrat cât <strong>de</strong> mic posibil, obiectul StateHol<strong>de</strong>r va avea <strong>de</strong> plătit preŃul<br />

• Variante ale şablonului<br />

Dacă Memento-ul trebuie să fie o clasă <strong>de</strong> sine stătătoare şi nu o clasă internă,<br />

trebuie <strong>de</strong>finite două interfeŃe - Wi<strong>de</strong>Memento şi NarrowMemento. InterfaŃa largă<br />

este pentru Originator-ul Memento-ului astfel încât el să poată accesa Memento-ul<br />

pentru a-si extrage starea. InterfaŃa restrânsă este pentru obiectele StateHol<strong>de</strong>r şi<br />

pentru alŃi clienŃi folosiŃi.<br />

40


• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Command - poate folosi Memento-uri pentru a urmări stările în ve<strong>de</strong>rea<br />

anulării unor acŃiuni<br />

- State<br />

• Exemplu<br />

Şablonul Memento poate 11 folosit, <strong>de</strong> exemplu, pentru a reŃine un număr:<br />

class Memento { ir.t num;<br />

Memento(int c) {<br />

num = c; } int<br />

getNum() {<br />

return num;<br />

x<br />

III.7. State<br />

• Cunoscut şi ca Objects For States<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: obiect<br />

Să schimbe uşor comportamentul unui obiect la rulare.<br />

• Introducere<br />

De multe ori, o aplicaŃie se comportă diferit în funcŃie <strong>de</strong> valorile variabilelor<br />

ei interne. De exemplu, când se lucrează cu un fişier text, acesta trebuie salvat din<br />

când în când. Multe dintre editoarele <strong>de</strong> text curente permit salvarea documentului<br />

doar când acesta s-a modificat. Imediat ce textul a fost salvat, el este consi<strong>de</strong>rat<br />

"curat"; conŃinutul fişierului este i<strong>de</strong>ntic cu cel afişat pe ecran.<br />

Implementarea acestui lucru într-o metodă individuală face codul greu <strong>de</strong><br />

menŃinut şi <strong>de</strong> citit. Aceste meto<strong>de</strong> vor conŃine structuri if/else. O tactică ar fi<br />

reŃinerea stării unui obiect într-o singură variabilă folosind constante pentru o valoare,<br />

caz în care meto<strong>de</strong>le vor conŃine structuri switch/case care vor fi asemănătoare în<br />

fiecare metodă.<br />

Obiectele reprezintă stare şi comportament; starea este păstrată în atributele lor<br />

iar comportamentul este <strong>de</strong>finit în meto<strong>de</strong>. Şablonul State permite schimbarea<br />

dinamică a comportamentului unui obiect. Acest comportament dinamic este obŃinut<br />

prin <strong>de</strong>legarea tuturor apelurilor <strong>de</strong> meto<strong>de</strong> care se bazează pe anumite valori către un<br />

41


obiect <strong>de</strong> tip State. Acest obiect este la rândul l u i comportamental, prin urmare<br />

schimbarea unor obiecte State duce la obŃinerea unui comportament diferit. Meto<strong>de</strong>le<br />

specifice din clasele State nu mai trebuie sa folosească structuri if/else sau<br />

switch/case; obiectul State <strong>de</strong>fineşte comportamentul pentru o singură stare.<br />

■ Utilizare<br />

Şablonul State se foloseşte când:<br />

- comportamentul obiectului <strong>de</strong>pin<strong>de</strong> <strong>de</strong> starea sa. aceasta schimbându-se<br />

frecvent<br />

- meto<strong>de</strong>le conŃin structuri condiŃionale mari care <strong>de</strong>pind <strong>de</strong> starea obiectului<br />

■ Descriere<br />

Obiectele care au un comportament diferit în funcŃie <strong>de</strong> starea lor curentă pot<br />

fi greu <strong>de</strong> implementat fără şablonul State. Implementarea fără acest şablon presupune<br />

folosirea <strong>de</strong> constante pentru urmărirea stării curentă şi implementarea unor structuri<br />

switch lungi. Majoritatea acestor meto<strong>de</strong> aflate în aceeaşi clasă au o structură similară.<br />

Consi<strong>de</strong>rând o uşa, care sunt operaŃiile normale care se pot face cu o simplă<br />

uşă? Aceasta poate fi <strong>de</strong>schisă şi închisă, <strong>de</strong>ci ea se poate afla în una din cele două<br />

stări - închis sau <strong>de</strong>schis. Apelarea meto<strong>de</strong>i <strong>de</strong> închi<strong>de</strong>re a unei uşi închise nu duce la<br />

nimic, dar apelarea acesteia pentru o uşa <strong>de</strong>schisă conduce la schimbarea stării uşii.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului State este următoarea:<br />

Context<br />

-State currentState<br />

+void setCurrentState(State s)<br />

i k<br />

i<br />

k T<br />

1 1 1 1<br />

__ L<br />

_<br />

interface State<br />

+void someMethod()<br />

------------- * ----------------<br />

ConcreteStateA ConcreteStateB<br />

+void someMethod()<br />

Implementarea şablonului State necesită:<br />

+void someMethodQ<br />

- Context - menŃine o referinŃă către starea curentă, fiind interfaŃa utilizată <strong>de</strong><br />

clienŃi<br />

- State - <strong>de</strong>fineşte meto<strong>de</strong>le care <strong>de</strong>pind <strong>de</strong> starea obiectului<br />

- ConcreteState - clasa care implementează interfaŃa State şi comportamentul<br />

specific unei stări<br />

42


Context sau ConcreteState pot <strong>de</strong>termina tranziŃiile între stări. Când numărul<br />

stărilor este fixat, cel mai apropiat loc în care se poate reŃine logica tranziŃiei este<br />

Context, lotuşi, se obŃine o flexibilitate mai mare dacă aceasta se plasează în<br />

subclasele clasei State. în acest caz. fiecare obiect State <strong>de</strong>termină tranziŃia - care este<br />

următoarea stare. în ce circumstanŃe şi când are loc tranziŃia. Acest lucru face mai<br />

uşoară schimbarea unei părŃi a obiectului State şi adăugarea unuia nou. Inconvenientul<br />

este că fiecare clasă care implementează clasa State <strong>de</strong>pin<strong>de</strong> <strong>de</strong> alte clase. Dacă<br />

implementarea clasei State <strong>de</strong>termină tranziŃia, interfaŃa Context trebuie să conŃină o<br />

calc pentru introducerea noii stări în context.<br />

• Beneficii şi inconveniente<br />

Printre beneficiile şi inconvenientele şablonului State se numără:<br />

- partiŃionarea comportamentului în funcŃie <strong>de</strong> stări - acest lucru oferă o<br />

ve<strong>de</strong>rea mai bună a comportamentului. Când un obiect se află într-o stare specifică,<br />

privind subclasele corespunzătoare clasei State se observă că toate comportamentele<br />

posibile ale acelei stări sunt incluse acolo<br />

- oferă structură, având o intenŃie clară - o variantă <strong>de</strong>s folosită a şablonului<br />

State este utilizarea constantelor şi a unei structuri switch pentru a <strong>de</strong>termina acŃiunile<br />

următoare. Aceasta este o soluŃie slabă <strong>de</strong>oarece creează duplicate. Multe meto<strong>de</strong><br />

folosesc aproape în acelaşi fel structura switch. Dacă se doreşte adăugarea unei noi<br />

stări, trebuie modificate toate meto<strong>de</strong>le clasei Context prin adăugarea unui nou<br />

element fiecărei structuri switch. Prin contrast, aceeaşi schimbare în sistem, folosind<br />

şablonul State, este realizată simplu prin crearea unei noi implementări a stării<br />

- tranziŃiile sunt explicite - când se folosesc constante pentru stări, este uşor să<br />

se confun<strong>de</strong> o schimbare <strong>de</strong> stare cu o atribuire a unei variabile <strong>de</strong>oarece sintactic<br />

arată la fel. Utilizând şablonul State, stările sunt compartimentate în obiecte, făcând<br />

mult mai uşoară recunoaşterea unei schimbări <strong>de</strong> stări<br />

- stările pot fi distribuite - dacă subclasele clasei State conŃin doar<br />

comportamente şi nu instanŃe ale variabilelor, ele <strong>de</strong>vin practic şabloane Flyweights.<br />

Orice stare <strong>de</strong> care au nevoie poate să le fie trimisă prin intermediul interfeŃei<br />

Context. Se reduce astfel numărul obiectelor din sistem<br />

- şablonul State foloseşte un număr mare <strong>de</strong> clase - acest lucru poate fi<br />

consi<strong>de</strong>rat un <strong>de</strong>zavantaj. Şablonul State creează cel puŃin o clasă pentru fiecare stare<br />

posibilă. Insă este <strong>de</strong> preferat acest lucru, alternativa fiind lungi structuri switch<br />

• Variante ale şablonului<br />

Unul din lucrurile importante în ceea ce priveşte şablonul State este<br />

<strong>de</strong>terminarea cui guvernează tranziŃiile dintre stări. O altă opŃiune, în afara subclaselor<br />

lui State şi Context, ar 11 privirea tranziŃiilor într-o structură <strong>de</strong> tabel, cu un tabel<br />

pentru fiecare stare. Se transformă astfel codul <strong>de</strong> tranziŃie într-o operaŃie <strong>de</strong> privire a<br />

unui tabel. Pentru a schimba criteriul <strong>de</strong> tranziŃie, doar datele din tabel trebuie<br />

schimbate în loc <strong>de</strong> a modifica codul. Dezavantajele sunt însă numeroase: tabelele<br />

sunt <strong>de</strong> multe ori mai ineficiente <strong>de</strong>cât apelul unei meto<strong>de</strong>; introducerea logicii unei<br />

tranziŃii într-un tabel o face mult mai greu <strong>de</strong> înŃeles. Principala diferenŃă este că<br />

şablonul State se concentrează pe mo<strong>de</strong>larea comportamentului în funcŃie <strong>de</strong> stări, pe<br />

când folosirea tabelelor se bazează pe tranziŃiile dintre diferite stări. O alăturare a<br />

acestor doua abordări combină dinamică mo<strong>de</strong>lului cu tabele cu şablonul State.<br />

43


TranziŃiile se stochează într-un obiect HashMap. dar în loc <strong>de</strong> a avea un tabel pentru<br />

fiecare stare, se creează un obiect HashMap pentru fiecare metodă din clasa State.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Flyweight - stările pot fi disponibile folosind acest şablon<br />

- Singleton - multe şabloane State sunt şabloane Singleton. în special atunci<br />

când sunt şi şabloane Flyweights<br />

• Exemplu<br />

Presupunem că utilizatorii se conectează la o bază <strong>de</strong> date pentru a efectua<br />

anumite acŃiuni. Se folosesc astfel două subclase Management şi Sales. pentru a se<br />

exemplifica şablonul State:<br />

abstract class Connection {<br />

public abstract void open(); public<br />

abstract void close ( ) ; public abstract;<br />

void log Ń ) ; }<br />

class Sales extends Connection {<br />

public void open() {<br />

Systerr.. out. println ( "<strong>de</strong>seh: <strong>de</strong>re bază <strong>de</strong> date pentru<br />

vânzări"); }<br />

public void close() {<br />

System.out.println("închi<strong>de</strong>re bază <strong>de</strong> date"); }<br />

public void log() {<br />

System.out.println("iocare activităŃi";;<br />

class Management extends Connection {<br />

public void open Ń) {<br />

System, out. println ( "<strong>de</strong>schi<strong>de</strong>re bază <strong>de</strong> date pentru<br />

management");<br />

\<br />

public void closet) {<br />

System.out.println("închi<strong>de</strong>re oază <strong>de</strong> date"); Ń<br />

public veid log() {<br />

System.out.println("logare activităŃi");<br />

class Controller public sta public<br />

static Management manage; private<br />

static Connection current;<br />

Controller() {<br />

sales =• new Sales (); manage =<br />

new Management(); }<br />

public void makeSalesConnecticn() { current - sales; }<br />

public void makeManagementConnection() { current -<br />

manaae; }<br />

44


public voia open ; ; { :.::: --•:/.. : :: n ; •<br />

public void close{} { :.::,:_:.:::;;.•; ;<br />

public void log ( ) { curr^r.~..l: ~ . ; }<br />

lass Test {<br />

Stririg con;<br />

Controller controller;<br />

Test (String con) {<br />

controller = new Controller!);<br />

ii Ń con . equalsIgnoreCa.se ; "management " ) )<br />

controller . makeManagementConr.ection î )<br />

i f { con.equaÎs IgnoreCase("sales") )<br />

controller.makeSalesConnection();<br />

controller.open(); controller.log();<br />

ccntroller.closeO ;<br />

lass Server {<br />

public static Test test;<br />

public static void main(String[] args) {<br />

new Test(args[O]);<br />

III.8. Strategy<br />

• Cunoscut şi ca Policy<br />

■ ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: componentă<br />

Să <strong>de</strong>finească un grup <strong>de</strong> clase care să reprezinte un set <strong>de</strong> comportamente<br />

posibile. Aceste comportamente pot fi apoi introduse uşor în aplicaŃie, schimbând<br />

după caz funcŃionalitatea.<br />

• Introducere<br />

Se presupune că managerul personal <strong>de</strong> informaŃii conŃine o listă <strong>de</strong> contacte.<br />

Pe măsură ce numărul acestora creşte, se doreşte existenŃa unei modalităŃi <strong>de</strong> sortare a<br />

intrărilor şi <strong>de</strong> vizualizare a informaŃiilor <strong>de</strong>spre un anumit contact. Pentru a face acest<br />

lucru, se poate crea o clasă care să înregistreze contactele în memorie, să le sorteze şi<br />

să afişeze informaŃiile <strong>de</strong>spre ele. Această cale duce la apariŃia unor probleme în timp,<br />

cea mai serioasă fiind aceea că soluŃia nu poate fi modificată şi extinsă uşor.<br />

45


De fiecare dată când se vrea introducerea unei noi variante <strong>de</strong> sortare şi <strong>de</strong><br />

afişare a informaŃiilor, trebuie modificată clasa care execută aceste operaŃii. Mai mult.<br />

o dată cu creşterea numărul <strong>de</strong> opŃiuni <strong>de</strong> sortare şi afişare, mărimea şi complexitatea<br />

codului se măreşte, făcându-1 mai greu <strong>de</strong> testat şi menŃinut.<br />

Dacă în schimb se <strong>de</strong>zvoltă o serie <strong>de</strong> clase, fiecare conŃinând o modalitate<br />

specifică <strong>de</strong> sortare şi afişare a contactelor? Clasa principală predă sarcina respectivă<br />

uneia dintre aceste clase, eliminându-se astfel codul complex al celeilalte soluŃii.<br />

Şablonul Strategv se bazează pe obiecte care au o stare şi un comportament,<br />

înlocuind un obiect cu un altul, are loc o schimbare a comportamentului, şi cu toate că<br />

astfel apar mai multe clase, fiecare dintre acestea este uşor <strong>de</strong> menŃinut iar soluŃia<br />

generală este foarte extensibilă.<br />

• Utilizare<br />

Şablonul Strategv se foloseşte când:<br />

- există mai multe căi <strong>de</strong> a efectua o acŃiune<br />

- nu se ştie cu exactitate ce cale să se folosească <strong>de</strong>cât în momentul rulării<br />

- se doreşte adăugarea uşoară a altor modalităŃi <strong>de</strong> efectuare a unei acŃiuni<br />

- se vrea un cod uşor <strong>de</strong> întreŃinut pe măsură ce se adaugă noi comportamente<br />

• Descriere<br />

De multe ori există mai multe căi <strong>de</strong> a efectua aceeaşi acŃiune. Sortarea, <strong>de</strong><br />

exemplu, poate fi tăcută cu ajutorul unor algoritmi cum ar fi quick-sort şi sortarea prin<br />

metoda bulelor, prin utilizarea câmpurilor multiple sau conform anumitor criterii.<br />

Când un obiect îşi poate atinge scopul prin mai multe căi, el <strong>de</strong>vine complex şi<br />

greu <strong>de</strong> administrat. Pentru salvarea unui document în diferite formate, trebuie scris<br />

un cod care să producă o clasă capabilă să reprezinte documentul respectiv şi să-1<br />

salveze conform cerinŃelor. O dată cu creşterea numărului formatelor şi a<br />

complexităŃii lor, administrarea codului într-o singură clasă <strong>de</strong>vine greoaie.<br />

în astfel <strong>de</strong> cazuri se poate şablonul Strategv pentru menŃinerea unui echilibru<br />

între flexibilitate şi complexitate. Acest şablon separă comportamentele unui obiect,<br />

reprezentându-le în câte o clasă separată. Obiectul foloseşte apoi comportamentul care<br />

satisface cerinŃele <strong>de</strong> la un moment dat. De exemplu, pentru un document se poate<br />

<strong>de</strong>zvolta câte o clasă care să-1 salveze în fiecare format, comportamentul acestor clase<br />

fiind <strong>de</strong>finit într-o supraclasă sau o interfaŃă.<br />

Şablonul Strategy administrează seturi <strong>de</strong> algoritmi <strong>de</strong> bază. cum ar fi căutarea<br />

şi sortarea. Poate fi folosit şi pentru interogarea bazelor <strong>de</strong> date. <strong>de</strong>finirea diferitelor<br />

modalităŃi <strong>de</strong> interogare sau organizarea rezultatelor. în spaŃiul afacerilor, el este<br />

câteodată utilizat pentru a reprezenta diferite posibilităŃi <strong>de</strong> efectuare a tranzacŃiilor.<br />

Comanda unei staŃii <strong>de</strong> lucru, <strong>de</strong> exemplu, poate fi implementată cu ajutorul<br />

şablonului Strategy dacă se doreşte achiziŃionarea uneia diferită <strong>de</strong> mo<strong>de</strong>lul standard.<br />

46


• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Strateg} este următoarea:<br />

Strateg} Client<br />

-Strategv strategv<br />

+void setStrategy(Strategy s)<br />

+void performOperationQ<br />

strategv. operationQ<br />

ConcreteStrategyB<br />

+void operationQ<br />

interface Strateg}'<br />

-void operalion()<br />

Pentru implementarea şablonului Stratcgy este nevoie <strong>de</strong>:<br />

ConcreteStrategyA<br />

+void operation()<br />

- StrategyClient - clasa care foloseşte diferite strategii pentru anumite sarcini.<br />

Ea păstrează o referinŃă către instanŃa Strategy pe care o foloseşte şi conŃine o metodă<br />

care înlocuieşte instanŃa Strategy curentă cu o altă implementare<br />

- Strategy - interfaŃa ce <strong>de</strong>fineşte toate meto<strong>de</strong> ce pot fi folosite <strong>de</strong> clasa<br />

StrategyClient<br />

- ConcreteStrategy - clasa care implementează interfaŃa Strategy. utilizând un<br />

set specific <strong>de</strong> reguli pentru fiecare metodă a interfeŃei<br />

• Beneficii şi inconveniente<br />

Fiecare comportament este <strong>de</strong>finit în propria-i clasă, astfel că şablonul<br />

Strategy conduce la un control mult mai uşor al comportamentelor. Totodată,<br />

extin<strong>de</strong>rea unui mo<strong>de</strong>l care să includă noi comportamente este mai facilă.<br />

Principala provocare în ceea ce priveşte acest şablon, este stabilirea modului<br />

exact <strong>de</strong> reprezentare a unui comportament. Fiecare Strategy trebuie să aibă aceeaşi<br />

interfaŃă pentru obiectul apelat. Trebuie i<strong>de</strong>ntificat unul generic, care să poată fi<br />

aplicat mai multor implementări, dar care în acelaşi timp să fie specific pentru<br />

diferitele strategii concrete folosite.<br />

■ Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Singleton - <strong>de</strong> multe ori implementările şablonului Strategy sunt reprezentate<br />

ca şabloane Singleton<br />

47


- Flyweight - câteodată obiectele <strong>de</strong> tip Strategy sunt proiectate ca obiecte <strong>de</strong><br />

tip Flyweights pentru a le face mai puŃin costisitoare <strong>de</strong> creat<br />

- Factory Method - şablonul Strateg) poate fi <strong>de</strong>finit ca un şablon Factory<br />

Method astfel încât clasa principală să utilizeze noi implementări ale şablonului iară a<br />

recoda alte părŃi ale aplicaŃiei<br />

Exemplu<br />

Un exemplu simplu al şablonului Strateg}- este prezentat. Se aruncă un zar şi în<br />

funcŃie <strong>de</strong> rezultat se afişează un mesaj:<br />

interface Fortur.eCookies { public void prinŃ (); }<br />

class Six implementa FortuneCookies { public void<br />

prinŃ() {<br />

System.out.prinŃIn("Perfect!");<br />

class Five irrpl emerit s FortuneCookies {<br />

public void prinŃ() {<br />

Systera. out. println ( "Destul <strong>de</strong> bine!");<br />

class t-our iniplements FortuneCookies {<br />

public void prinŃ() {<br />

System.out.crintln("Bine!");<br />

lass Three implements FortuneCookies {<br />

public void prinŃ() {<br />

System.cut.printin("Se poate şi mai bine!")<br />

class Two implements FortuneCookies {<br />

public void prinŃ () {<br />

lass One implements FortuneCookies {<br />

public void prinŃ() {<br />

System.out.println("Slab!")<br />

lass Nuli impl emerit s FortuneCookies {<br />

public void prinŃ {) {<br />

Syst em. ou c . pr int ^n ( "N — mic ! "<br />

cl ass D ice {<br />

p u b l i c i n t t h r o w l t ( ) {<br />

r e t u r n ( i nt ) ( Ma t h . r an d o m ( )" 6 ) +1 ;<br />

class lest {<br />

static void goodFortune() {<br />

irit luckyNum = new Di ce ( ) . throwlt ( ) ;<br />

FortuneCookies fc; s w i t c h (Iu c k y M u rr.) {<br />

case 1: fc = new On e( ) ; b re a k;<br />

case 2: Le = new Tw o( ) ; b re a k;<br />

48


f c . p r i n t ( ) ; }<br />

public static vcid iru<br />

gocdFortune();<br />

III.9. Visitor •<br />

ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: componentă<br />

Ci^se ' : : i : -- :. . ■ ; _ : . : -^ - ; creak;<br />

case ; : : : : : = : ^ : _.._ ; ivreak;<br />

<strong>de</strong>fault: zz -- r ev :: J 1I . ; ;<br />

Să pună la dispoziŃie o cale uşoară <strong>de</strong> a efectua acŃiuni pentru o familie <strong>de</strong><br />

clase. El centralizează comportamentele şi permite ca ele să fie modificate sau extinse<br />

tară a modifica clasele care le folosesc.<br />

• Introducere<br />

Se doreşte ca managerul personal <strong>de</strong> informaŃii să conŃină capacităŃi <strong>de</strong><br />

planificare, iar planificatorul să fie folosit pentru lucruri ca licitaŃiile, analizele <strong>de</strong> risc<br />

şi estimarea timpului. Următoarele reprezintă un proiect complex:<br />

- Project - rădăcina ierarhiei proiectului, reprezentând proiectul în sine<br />

- Task - o sarcină în cadrul proiectului<br />

- Depen<strong>de</strong>ntTask - o sarcină care <strong>de</strong>pin<strong>de</strong> <strong>de</strong> alta<br />

- Deliverable - un articol sau document ce reprezintă rezultatul proiectului<br />

Pentru i<strong>de</strong>ntificarea clară a acestor clase ca părŃi ale unui mo<strong>de</strong>l, ele sunt<br />

organizate în jurul unei interfeŃe numite Projectitem. Până aici totul este în regulă.<br />

Dar cum se poate coda abilitatea <strong>de</strong> a estima costul total al proiectului? Acest calcul<br />

va <strong>de</strong>pin<strong>de</strong> probabil <strong>de</strong> tipul specific al interfeŃei Projectitem. în această interfaŃă se<br />

<strong>de</strong>fineşte o metoda getCost care trebuie să calculeze costul pentru o parte specifică a<br />

proiectului. Acest lucru pennite calcului costului pentru fiecare articol din structura<br />

proiectului. Se poate <strong>de</strong>ci<strong>de</strong> asupra unei modalităŃi <strong>de</strong> genul:<br />

- Project - tară operaŃii, <strong>de</strong> vreme ce costul este egal cu costul tuturor<br />

articolelor proiectului<br />

- SimpleTask - costul este calculat pe baza orelor în care s-a lucrat<br />

- Depen<strong>de</strong>ntTask - la fel ca sarcina simplă, dar adăugându-se un factor<br />

adiŃional care reprezintă <strong>de</strong>pen<strong>de</strong>nŃa unei sarcini <strong>de</strong> alta<br />

- Deliverable - costul este o estimare <strong>de</strong> bază a materialelor plus costul <strong>de</strong><br />

producŃie<br />

49


Totuşi, cum se poate calcula timpul necesar pentru rezolvarea proiectului,<br />

precum şi riscul? Folosind aceeaşi metodă ca şi în cazul celorlalte costuri face codul<br />

greu <strong>de</strong> întreŃinut. Trebuie scrise o grămadă <strong>de</strong> noi meto<strong>de</strong> care vor fi împrăştiate prin<br />

toate clasele proiectului. Cu fiecare nouă operaŃie, clasa <strong>de</strong>vine din ce în ce mai largă,<br />

mai complexă şi mai greu <strong>de</strong> înŃeles. De asemenea este dificil <strong>de</strong> a Ńine evi<strong>de</strong>nŃa<br />

informaŃiilor. Dacă se doreşte estimarea costului, a timpului sau a riscului folosind<br />

astfel <strong>de</strong> meto<strong>de</strong>, trebuie găsită o modalitate <strong>de</strong> păstrare a rezultatelor intermediare, <strong>de</strong><br />

vreme ce fiecare metodă aparŃine unui obiect specific al proiectului. Se ajunge astfel<br />

la trimiterea informaŃiilor prin întreaga structură a proiectului.<br />

Şablonul Visitor oferă o alternativă. Se <strong>de</strong>fineşte o singură clasă <strong>de</strong>numită<br />

CostProjectVisitor, care efectuează toate calculele legate <strong>de</strong> cost. în loc <strong>de</strong> a efectua<br />

aceste calcule în cadrul fiecărui articol al proiectului, acestea se fac <strong>de</strong> către clasa<br />

Visitor, care reŃine şi costul total. InterfaŃa Projectltem nu va mai conŃine metoda<br />

getCost. în schimb, va avea o metodă acceptVisitor mult mai generică, care foloseşte<br />

un obiect <strong>de</strong> tip ProjectVisitor pentru a apela o metodă specifică din clasa<br />

ProjectVisitor. De exemplu, metoda acceptVisitor pentru o anumită sarcină apelează<br />

metoda visitTask a interfeŃei Visitor. Dacă aceasta este <strong>de</strong> tipul CostProjectVisitor,<br />

atunci metoda visitTask calculează costul asociat sarcinii respective.<br />

Acest mo<strong>de</strong>l oferă beneficii substanŃiale, cel mai important fiind acela că se<br />

pot adăuga uşor noi operaŃii. Pentru calculul timpului trebuie doar scrisă o clasă<br />

TimeProjectVisitor care să conŃină toate meto<strong>de</strong>le necesare pentru a calcula timpul în<br />

care s-a lucrat la proiect. Codul pentru obiectele proiectului rămâne neschimbat,<br />

<strong>de</strong>oarece el conŃine <strong>de</strong>ja apeluri către meto<strong>de</strong>le generice <strong>de</strong>finite în clasa<br />

ProjectVisitor.<br />

Mai mult. şablonul Visitor conŃine un loc pentru centralizarea situaŃiei. Pentru<br />

clasa CostProjectVisitor se pot stoca rezultatele intermediare chiar în Visitor, în timp<br />

ce se efectuează calculele costului. Codul pentru centralizarea estimării face uşoară<br />

ajustarea calculelor <strong>de</strong> bază. Prin folosirea şablonul Visitor, se pot adaugă uşor<br />

caracteristici cum ar fi factori adiŃionali, putându-se calcula <strong>de</strong> exemplu discount-ul.<br />

• Utilizare<br />

Şablonul Visitor se foloseşte atunci când sunt în<strong>de</strong>plinite următoarele condiŃii:<br />

- un sistem conŃine un grup <strong>de</strong> clase asociate<br />

- câteva operaŃii netriviale trebuie efectuate <strong>de</strong> unele sau <strong>de</strong> toate clasele<br />

asociate<br />

- operaŃiile trebuie efectuate diferit pentru clasele variate<br />

• Descriere<br />

Şablonul Visitor implică preluarea unor operaŃii asociate dintr-un grup <strong>de</strong> clase<br />

şi plasarea lor împreună într-o singură clasă. Motivul este întreŃinerea codului - în<br />

unele situaŃii <strong>de</strong>vine prea complicat <strong>de</strong> întreŃinut operaŃiile în cadrul fiecărei clase.<br />

Şablonul Visitor este folositor în aceste cazuri, <strong>de</strong>oarece conŃine un suport generic<br />

pentru susŃinerea operaŃiilor unui grup <strong>de</strong> clase.<br />

El necesită ca toate clasele ce conŃin operaŃii sau Elemente, să aibă şi o metodă<br />

<strong>de</strong> acceptare care să fie apelată atunci când Visitor-ul efectuează o operaŃie asupra<br />

unui Element. Argumentul acestei meto<strong>de</strong> <strong>de</strong> acceptare este o instanŃă a Visitor-ului.<br />

50


Fiecare implementare a unui Element conŃine metoda <strong>de</strong> acceptare care<br />

apelează metoda <strong>de</strong> vizitare din cadrul Yisitor-ului. Fiecare Visitor implementează o<br />

metodă <strong>de</strong> vizitare specifică subtipului Element-ului.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Visitor este următoarea:<br />

interface Visitor<br />

+void visit(ConcreteElementA cmElementA)<br />

+void visitfConcreteElc'mcntB anElementB)<br />

ConcreteVisitorA Concrete VisitorB<br />

+void visit(ConcreteElementA anElementA)<br />

+void visit(ConcreteElementB anElementB)<br />

interface Element<br />

+void accept (Visitor visitor)<br />

+void visit(ConcreteElementA anElementA)<br />

+void visit(ConcreteElementB anElementB)<br />

ConcreteElementA ConcreteElementB<br />

+void accept(Visitor visitor) +void accept(Visitor visitor)<br />

visitor. visit(this) visitor.visit(this)<br />

Pentru implementarea şablonului Visitor se folosesc următoarele:<br />

- Visitor - clasa abstractă sau interfaŃa care <strong>de</strong>fineşte o metodă <strong>de</strong> vizitare<br />

pentru fiecare clasă ConcreteElement<br />

- ConcreteVisitor - clasa ce reprezintă o operaŃie specifică ce trebuie efectuată<br />

în cadrul sistemului. Implementează toate meto<strong>de</strong>le <strong>de</strong>finite în Visitor pentru o<br />

operaŃie specifică sau un algoritm<br />

- Element - clasa abstractă sau interfaŃa asupra căruia Visitor-ul operează.<br />

Minim, ea <strong>de</strong>fineşte o metodă <strong>de</strong> acceptare care primeşte un Visitor ca argument<br />

- ConcreteElement - entitate specifică a sistemului. Implementează metoda <strong>de</strong><br />

acceptare <strong>de</strong>finită în Element, apelând metoda <strong>de</strong> vizitare corespunzătoare <strong>de</strong>finită în<br />

Visitor<br />

Un lucru care trebuie urmărit cu atenŃie atunci când se implementează şablonul<br />

Visitor este supraîncărcarea meto<strong>de</strong>lor. Şablonul foloseşte supraîncărcarea meto<strong>de</strong>lor<br />

pentru metoda <strong>de</strong> vizitare. InterfaŃa Visitor poate avea două meto<strong>de</strong> <strong>de</strong> vizitare,<br />

fiecare primind un alt argument.<br />

51


■ Beneficii şi inconveniente<br />

Datorita structurii sale. şablonul Visitor tace uşoară adăugarea <strong>de</strong> noi<br />

comportamente sistemului. Când se implementează iniŃial şablonul, se <strong>de</strong>zvoltă un<br />

cadru <strong>de</strong> suport pentru fiecare altă acŃiune a Visitor-ului ce se poate efectua în viitor.<br />

Pentru a adaugă o nouă funcŃionalitate, se creează o nouă clasă care implementează<br />

interfaŃa Visitor şi se scrie noul cod.<br />

Şablonul Visitor este folositor <strong>de</strong>oarece permite centralizarea codului pentru o<br />

operaŃie, acest lucru tăcând mai facilă întreŃinerea acestuia. Acelaşi obiect <strong>de</strong> Ńip<br />

Visitor este utilizat în mod normal pentru vizitarea fiecărui Element din structură, prin<br />

urmare el pune la dispoziŃie o locaŃie centrală pentru reŃinerea datelor colectate sau<br />

pentru stocarea rezultatelor intermediare.<br />

Partea rea a acestui şablon este aceea că flexibilitatea este scăzută în lanŃul<br />

claselor Element. Orice adăugare sau modificare a ierarhiei acestor clase are o mare<br />

şansă <strong>de</strong> a produce o rescrie a codului structurii Visitor. Orice clasă adiŃională<br />

necesită că o nouă metodă să fie <strong>de</strong>finită în interfaŃa Visitor şi fiecare ConcreŃeVisitor<br />

trebuie să conŃină o implementare a acestei meto<strong>de</strong>. Mai mult, şablonul poate încalcă<br />

principiul încapsulării. Şablonul Visitor preia codul care se aplică unui obiect în afara<br />

clasei obiectului şi îl mută într-o nouă locaŃie.<br />

• Variante ale şablonului<br />

Ca multe alte şabloane, Element-ul şi Visitor-ul se poŃ reprezenta în Java ca<br />

interfeŃe sau clase abstracte. O altă <strong>de</strong>cizie ce trebuie luată este cum să fie aplicat<br />

Visitor-ul unei colecŃii <strong>de</strong> Elemente. Şablonul Visitor nu are nici o <strong>de</strong>scriere privind<br />

structura <strong>de</strong> Elemente asupra căreia operează. Se poate folosi un ConcreŃeVisitor la<br />

fel <strong>de</strong> eficient pentru parcurgerea unei colecŃii simple, unei liste sau unui arbore.<br />

Deşi unele implementări ale Visitor-ului conŃin codul <strong>de</strong> parcurgere în<br />

interiorul ConcreteVisitor-ului, şablonul nu necesită acest lucru. Se poate folosi o<br />

clasă externă, <strong>de</strong> exemplu un Iterator. pentru mişcarea într-o colecŃie. Se poŃ apoi uni<br />

aceste două şabloane, Visitor şi Iterator, în funcŃie <strong>de</strong> cerinŃe.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Interpreter - se poate folosi şablonul Interpretei' pentru centralizarea<br />

interpretărilor operaŃiilor<br />

- IŃerator - se poate folosi şablonul Iterator pentru parcurgerea unei colecŃii<br />

generice<br />

- Composite - se poate combina şablonul Composite cu Visitor în ve<strong>de</strong>rea<br />

parcurgerii unei structuri arborescente<br />

<strong>de</strong> a<br />

1<br />

Exemplu • Exemplu<br />

Următorul exemplu foloseşte şablonul Visitor pentru a<br />

reprezenta modalităŃi comanda pizza <strong>de</strong> la diferite restaurante:<br />

interface Visitor { public void visit (Pizza p)<br />

interface Pizza { public Suring or<strong>de</strong>r(); }<br />

52


class ropjohn implementa -i z z; ; ■<br />

final String name - "Z :L "'::.:.'<br />

public String or<strong>de</strong>r;; ■. L r i<br />

\<br />

class FizzaHut impiements Fizza •.<br />

fina; String name --= "Fizz-Fu~<br />

pubizc String craer() { zoru:<br />

class GodFather impiements Fizza •;<br />

final String name = "GodFather"; public<br />

String or<strong>de</strong>r () { return nanie; }<br />

class ByPickup impiements Visitcr {<br />

private String name;<br />

private fina] String methcd = "Ry pick uc"; public<br />

void visit(Fizza p) { name = p.or<strong>de</strong>r(); } public<br />

String toString() { return nair.e - " " + methoc<br />

class ByDeiivery impiements Visitcr {<br />

private String name;<br />

private final String method = "Ey <strong>de</strong>livery"; public<br />

void visit(Fizza p) { name = p.or<strong>de</strong>r(); } public<br />

String roStringf) { return name + " " + methoc<br />

class Dinner {<br />

public Pizza getDinner() {<br />

switch ((int)(Math.random(;*3)){<br />

case 0: return new PopJohn(); break; case 1:<br />

return new PizzaHut () ; break; case 2:<br />

return new GodFather(); break; <strong>de</strong>fault:<br />

return nuli; }<br />

public Visitor howto() {<br />

switch ( (int) (Math.random()*2) ) {<br />

case 0: return new ByPickup(); break;<br />

case 1: return new ByDeiivery(); break;<br />

<strong>de</strong>fault: return nuli;<br />

class Test {<br />

public static void main(String[] args) { List<br />

pizzaList = new ArrayList(); pizzaList.add(new<br />

PopJohn () ) ; pizzaList.add(new PizzaHut () ) ; pi<br />

z.zaList . add (new 7 GodFather () ) ; Iteratcr it =<br />

pizzaList.iterator(); while (it.hasNext()) {<br />

System.out.prinŃIn(((Fizza)it.next()).or<strong>de</strong>r());<br />

Dinner d i; new Dinner () ;<br />

Fizza pza = d.getDinner();<br />

Visitor v = d.howtoŃ);<br />

v.visit(pza);<br />

System.out.prinŃin(v);<br />

53


111.10. Template Method<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: comportamental<br />

- Nivel: obiect<br />

Să pună la dispoziŃie o metodă care să permită subclaselor să suprascrie părŃi<br />

dintr-o metodă Iară a o rescrie.<br />

■ Introducere<br />

Când se lucrează cu proiecte, se doreşte frecvent estimarea costului pentru<br />

efectuarea unei anumite sarcini sau pentru producerea rezultatului. Managerul<br />

personal <strong>de</strong> informaŃii foloseşte un număr <strong>de</strong> clase pentru a reprezenta proiectele.<br />

Minim, clasele Task şi Deliverable sunt utilizate pentru reprezentarea elementelor<br />

proiectului. Pe măsură ce un proiect <strong>de</strong>vine mai complex, trebuie create clase<br />

adiŃionale cum ar fi Project sau Depen<strong>de</strong>ntTask pentru a satisface nevoile mai<br />

sofisticate. Cu toate că se poate crea o metoda getCostEstimate pentru fiecare clasă în<br />

parte, o astfel <strong>de</strong> modalitate implică mult cod duplicat. Numărul claselor crescând,<br />

<strong>de</strong>vine din ce în ce mai dificil <strong>de</strong> întreŃinut codul din toate clasele proiectului.<br />

O abordare mai bună este gruparea tuturor claselor asociate proiectului sub o<br />

supraclasă şi <strong>de</strong>finirea meto<strong>de</strong>i getCostEstimate acolo. Dar ce se poate face atunci<br />

când părŃi din metoda getCostEstimate <strong>de</strong>pind <strong>de</strong> informaŃii specifice fiecărei clase a<br />

proiectului? Daca obiectul <strong>de</strong> tip Task are o cale diferită <strong>de</strong> calculare o orelor faŃă <strong>de</strong><br />

obiectul <strong>de</strong> tip Deliverable?<br />

în acest caz, metoda getCostEstimate trebuie <strong>de</strong>finită astfel încât să apeleze o<br />

metodă abstractă getTimeRequired şi să permită claselor Task şi Deliverable să<br />

<strong>de</strong>finească metoda cât mai convenabil. Această modalitate, numită Template Method.<br />

aduce beneficii în ceea ce priveşte reutilizarea codului, permiŃând în acelaşi timp<br />

claselor să modifice anumite părŃi ale comportamentului în funcŃie <strong>de</strong> necesitaŃi.<br />

• Utilizare<br />

Şablonul Template Method se foloseşte pentru:<br />

- a pune la dispoziŃie o structură schelet pentru o metodă, permiŃând<br />

subclaselor să re<strong>de</strong>finească părŃi specifice din metodă<br />

- a centraliza părŃi ale unei meto<strong>de</strong> care sunt <strong>de</strong>finite în toate subtipurile unei<br />

clase, dar care vor avea întot<strong>de</strong>auna o mică diferenŃă în fiecare clasă<br />

- a controla ce operaŃii subclasele au voie a suprascrie<br />

• Descriere<br />

Când se construieşte o ierarhie complexă <strong>de</strong> clase pentru aplicaŃie, codul este<br />

<strong>de</strong> multe ori duplicat în anumite locuri. Acest lucru nu este <strong>de</strong> dorit, <strong>de</strong> vreme ce se<br />

doreşte reutilizarea codului oricât <strong>de</strong> mult. Refacerea codului astfel încât meto<strong>de</strong>le să<br />

se alia în supraclasă este un pas în direcŃia bună.<br />

54


Problema este că o operaŃie care a fost refăcută se bazează pe informaŃia<br />

specifică care este valabilă doar în subclasă. Din această cauză, <strong>de</strong>seori se acceptă<br />

codul duplicat în clase multiple.<br />

Când multe meto<strong>de</strong> din clase asociate au o structură similară, şablonul<br />

Template Method este <strong>de</strong> folos. Mai întâi, se <strong>de</strong>termină care părŃi ale meto<strong>de</strong>lor sunt<br />

similare. Aceste părŃi trebuie centralizate în supraclasă. în timp ce celelalte operaŃii<br />

rămân în subclase. Metoda Template nou <strong>de</strong>finită conŃine structura operaŃiei. Pentru<br />

fiecare parte a operaŃiei care variază, o metodă abstractă este <strong>de</strong>finită în supraclasă.<br />

Subclasele suprascriu aceste meto<strong>de</strong> punând la dispoziŃie propria lor implementare.<br />

Când este apelată metoda template în subclasă, codul din supraclasă este executat.<br />

Când metoda template din supraclasă este <strong>de</strong>clarată final, subclasele sunt limitate în<br />

ceea ce priveşte părŃile supraclasei pe care le pot suprascrie.<br />

Acest şablon este <strong>de</strong>numit Template Method <strong>de</strong>oarece pune la dispoziŃie o<br />

metodă ce conŃine structura operaŃiei, dar lasă unele uşi <strong>de</strong>schise prin apelarea <strong>de</strong><br />

meto<strong>de</strong> abstracte. Este exact ca un template. <strong>de</strong>oarece subclasele umplu spaŃiile goale<br />

conŃinând implementări pentru meto<strong>de</strong>le abstracte.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Template Method este următoarea:<br />

AbstractClass<br />

+void templateMethod()<br />

+void subOperation 1 ()<br />

+void sub()peration2()<br />

i<br />

ConcreteClass<br />

+void subOperationl()<br />

+void subOperation2()<br />

//'cod schelet<br />

subOperation 1() "mai<br />

mult cod schelet<br />

subOperation2() //si<br />

mai mult cod<br />

Pentru implementarea şablonului Template Method este nevoie <strong>de</strong>:<br />

- AbstractClass - clasa abstractă ce conŃine metoda template şi <strong>de</strong>fineşte una<br />

sau mai multe meto<strong>de</strong> abstracte. Metoda template conŃine codul schelet şi apelează<br />

una sau mai multe meto<strong>de</strong> abstracte. Pentru a preveni subclasele să suprascrie metoda<br />

template. aceasta trebuie <strong>de</strong>clarată final<br />

- ConcreteClass - extin<strong>de</strong> clasa AbstractClass şi implementează meto<strong>de</strong>le<br />

abstracte ale acesteia. Se bazează pe clasa AbstractClass pentru a pune la dispoziŃie<br />

structura operaŃiei conŃinută în metoda template


• Beneficii şi inconveniente<br />

Principalul beneficiu al şablonului Template Method este acela că permite<br />

reutilizarea codului. Fără acest şablon, codul este duplicat în mai multe subclase.<br />

Acest beneficiu face şablonul Template Method esenŃial pentru cadre. Un cadru<br />

conŃine mai multe meto<strong>de</strong> care doar minimal se bazează pe implementările specifice<br />

din subclasa. Folosind acest şablon înseamnă că întreaga structură poate fi pusă la<br />

dispoziŃie <strong>de</strong> cadru.<br />

Dacă metoda template apelează prea multe meto<strong>de</strong> abstracte, după ceva timp<br />

folosirea clasei AbstractClass că o supraclasă <strong>de</strong>vine plictisitoare. Este mai bine ca<br />

metoda template să apeleze un număr limitat <strong>de</strong> meto<strong>de</strong> abstracte.<br />

• Variante ale şablonului<br />

O variantă este ca şablonul Template Method să apeleze meto<strong>de</strong> concrete în<br />

loc <strong>de</strong> meto<strong>de</strong> abstracte. Clasa AbstractClass conŃine o implementare <strong>de</strong> bază pentru<br />

fiecare din meto<strong>de</strong>le apelate <strong>de</strong> Template Method. Aceste meto<strong>de</strong> sunt <strong>de</strong>numite<br />

meto<strong>de</strong> cârlig.<br />

RaŃiunea este că atunci când se foloseşte clasa AbstractClass, nu mai trebuie<br />

suprascrise meto<strong>de</strong>le pentru a putea folosi şablonul Template Method. AbstractClass<br />

nici nu trebuie sa fie abstractă.<br />

O responsabilitate a celui care implementează şablonul Template Method este<br />

să se documenteze în privinŃa meto<strong>de</strong>lor care sunt folosite în alte meto<strong>de</strong> template. în<br />

şablonul Template Method normal, este clar ce meto<strong>de</strong> trebuie suprascrise, <strong>de</strong>oarece<br />

toate aceste meto<strong>de</strong> sunt abstracte. Dacă meto<strong>de</strong>le cârlig nu sunt menŃionate în<br />

documentaŃie, ele nu pot fi i<strong>de</strong>ntificate.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Factory Method - meto<strong>de</strong>le template apelează <strong>de</strong>seori meto<strong>de</strong> factory pentru<br />

a crea instanŃe iară a cunoaşte clasele exacte ce se creează<br />

- Strategy - acest şablon foloseşte compunerea pentru a înlocui complet<br />

comportamentul, în timp ce şablonul Template Method foloseşte moştenirea pentru a<br />

înlocui părŃi ale comportamentului<br />

- Intercepting Filter - foloseşte şablonul Template Method pentru a<br />

implementa strategia Template Filter<br />

Exemplu<br />

Atunci când se face un împrumut, trebuie să se parcurgă o serie <strong>de</strong> paşi.<br />

Şablonul Template Method se foloseşte pentru a menŃine împreună aceşti paşi. tară a<br />

consi<strong>de</strong>ra implementarea reală a subclaselor:<br />

abstract class CheckBackgrcund {<br />

public abstract; void checkBankŃ) ;<br />

public abstract voia checkCredit();<br />

public abstract void checkLoan{);<br />

public abstract void checkStock();<br />

public abstract void checklr.come Ń ) ;<br />

56


public voia chec'-:..;<br />

checkEar:.


IV. Şabloane structurale<br />

Şabloanele structurale <strong>de</strong>scriu căi efective atât <strong>de</strong> partiŃionare cât şi <strong>de</strong><br />

combinare a elementelor unei aplicaŃii. Modul în care aceste şabloane influenŃează<br />

aplicaŃiile variază. De exemplu, şablonul Adapter poate realiza comunicarea între<br />

doua sisteme incompatibile. în vreme ce Faca<strong>de</strong> permite crearea unei interfeŃe simple<br />

cu utilizatorul fără a elimina toate opŃiunile valabile din sistem.<br />

IV. 1. Adapter<br />

• Cunoscut şi ca Wrapper<br />

• ProprietăŃi<br />

■ Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să acŃioneze ca un intermediar între dou clase, convertind interfaŃa unei clase<br />

astfel încât să poată fi folosită şi <strong>de</strong> cealaltă.<br />

• Introducere<br />

Unul dintre marile avantaje ale programării orientate pe obiecte este acela că<br />

permite reutilizarea codului. De vreme ce datele şi comportamentul sunt centralizate<br />

într-o clasă, se poate - cel puŃin în principiu - muta clasa dintr-un proiect într-altul şi<br />

reutiliza funcŃionalitatea tară prea mare efort. Din păcate, necunoscându-se cerinŃele<br />

codului pentru viitoarele proiecte, nu se ştie mereu cum să se schiŃeze clasa pentru o<br />

reutilizare optimă.<br />

De exemplu, pentru a grăbi <strong>de</strong>zvoltarea managerului personal <strong>de</strong> informaŃii, se<br />

<strong>de</strong>ci<strong>de</strong> cooperarea cu o altă persoană dintr-o altă Ńară. Această persoană lucrează la o<br />

aplicaŃie similară şi poate pune la dispoziŃie o implementare a unor componente ale<br />

aplicaŃiei. Dar atunci când se primesc fişierele, interfeŃele nu se potrivesc. Mai mult,<br />

codul este în altă limbă. Apar două soluŃii, amândouă neatrăgătoare.<br />

Prima opŃiune este aceea <strong>de</strong> a rescrie noua componentă astfel încât să poată<br />

implementa toate cerinŃele interfeŃei. Rescrierea noii componente este o i<strong>de</strong>e rea<br />

<strong>de</strong>oarece trebuie făcut acest lucru <strong>de</strong> fiecare dată când se primeşte o versiune înnoită a<br />

componentei respective.<br />

A doua opŃiune ar fi rescrierea aplicaŃiei folosind interfaŃa primită.<br />

Inconvenientul este că trebuie trecut prin tot codul pentru a modifica fiecare apariŃie a<br />

vechii interfeŃe, codul <strong>de</strong>venind astfel greu <strong>de</strong> înŃeles <strong>de</strong>oarece nu se cunoaşte limba în<br />

care este scrisă componenta primită.<br />

Este nevoie aici <strong>de</strong> un translator. Aici intervine şablonul Adapter. El se<br />

comportă similar unui adaptor <strong>de</strong> curent, convertind un tip în altul, altminteri<br />

incompatibile. Folosind acest şablon, aplicaŃia poate folosi interfaŃa proprie,<br />

permiŃând în acelaşi timp şi utilizarea noii componente. Când soseşte o versiune<br />

înnoită, singurul lucru ce trebuie modificat este Adapter-ul.<br />

58


:<br />

■ Utilizare<br />

Şablonul Adapter se foloseşte când:<br />

- se doreşte utilizarea unui obiect într-un mediu care aşteaptă o interfaŃă care<br />

este diferită <strong>de</strong> cea a obiectului<br />

- trebuie să existe o traducere a interfeŃelor între mai multe surse<br />

- un obiect trebuie să acŃioneze ca intermediar pentru un grup <strong>de</strong> clase,<br />

necunoscându-se care clasa va fi folosită <strong>de</strong>cât la rulare<br />

• Descriere<br />

Câteodată se doreşte folosirea unei clase într-un cadru nou fără a o recoda<br />

încât să se potrivească noului mediu. în astfel <strong>de</strong> cazuri, se poate proiecta o clasă<br />

Adaptee care să se comporte ca un translator. Această clasă primeşte apeluri <strong>de</strong> la<br />

mediu şi modifică apelurile pentru ca acestea să fie compatibile cu clasa Adaptee.<br />

Medii tipice în care un Adapter este folositor includ aplicaŃiile care suportă<br />

comportament plug-in cum ar fi graficele, textele, editoarele media sau browser-ele<br />

web. Un exemplu în lumea reală al şablonului Adapter o reprezintă un translator care<br />

realizează traducerea expresiilor comune dintr-un limbaj în altul, permiŃând<br />

comunicarea între doi indivizi altfel incompatibili.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Adapter este următoarea:<br />

Framework<br />

-Adapter adapter<br />

r-void performOperation()<br />

Adapter<br />

-Adaptee adaptee<br />

+void operaŃi on()<br />

Adaptee<br />

+void adaptedOperationQ<br />

Pentru implementarea şablonului Adapter este nevoie <strong>de</strong>:<br />

adapter.operationQ<br />

adaptee.adaptedOperationQ<br />

- Framework - foloseşte interfaŃa Adapter. Această clasă fie construieşte clasa<br />

ConcreteAdapter. fie este fixată în altă parte<br />

- Adapter - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le pe care le foloseşte clasa<br />

Framework<br />

59


- ConcreteAdapter - clasa care implementează interfaŃa Adapter. Ea păstrează<br />

o referinŃă către interfaŃa Adaptee şi traduce apelurile <strong>de</strong> meto<strong>de</strong> <strong>de</strong> la clasa<br />

Framework în apeluri <strong>de</strong> meto<strong>de</strong> în interfaŃa Adaptee. Această traducere poate implica<br />

şi ascun<strong>de</strong>rea sau modificarea parametrilor şi tipurilor rcturnate<br />

- Adaptee - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le tipului ce va fi adaptat<br />

- ConcreteAdaptee - clasa ce implementează interfaŃa Adaptee. Ea trebuie<br />

adaptată pentru a putea fi folosită <strong>de</strong> Framework<br />

• Beneficii şi inconveniente<br />

Şablonul Adapter oferă o reutilizare eficientă, permiŃând interacŃiunea dintre<br />

două sau mai multe obiecte altfel incompatibile. Totuşi, este nevoie <strong>de</strong> multă<br />

planificare în ve<strong>de</strong>rea <strong>de</strong>zvoltării unui cadru suficient <strong>de</strong> flexibil pentru a fi adaptat<br />

convenabil. Această problemă are două aspecte: structura funcŃională şi traducerea<br />

parametrilor.<br />

Dacă există o nepotrivire funcŃională între apelul trimis către Framework şi<br />

Adaptee, Adapter-ul trebuie să administreze necesităŃile <strong>de</strong> apel ale interfeŃei Adaptee.<br />

invocând orice meto<strong>de</strong> necesare înainte <strong>de</strong> a trimite apelul către Framework.<br />

O altă provocare a Adapter-ului este aceea <strong>de</strong> transfer a parametrilor, <strong>de</strong> vreme<br />

ce parametrii trimişi nu sunt întot<strong>de</strong>auna compatibili între Framework şi Adaptee. In<br />

astfel <strong>de</strong> cazuri, Adapter-ul fie creează un obiect apropiat atunci când nu există nici un<br />

echivalent direct între cele doua medii, fie învăluie un obiect pentru a-1 face utilizabil<br />

<strong>de</strong> către interfaŃa Adaptee.<br />

• Variante ale şablonului<br />

Adaptorii sunt dinamici şi foarte rar se pot ve<strong>de</strong>a doi care să fie i<strong>de</strong>ntici. Există<br />

însă unele variante:<br />

- MulŃi-Adaptee Adapters - în funcŃie <strong>de</strong> <strong>proiectare</strong>a sistemului, poate fi foarte<br />

avantajos ca un Adapter să fie o parte a Framework-ului apelat. Un astfel <strong>de</strong> Adapter<br />

se comportă <strong>de</strong> obicei ca un intermediar între sistem şi mai multe interfeŃe Adaptee<br />

- Non-lnterface-based Adapters - folosirea interfeŃelor în Java face posibilă<br />

<strong>de</strong>zvoltarea unor adaptori flexibili. Dar nu este mereu posibilă utilizarea interfeŃelor.<br />

De exemplu, nu este posibilă atunci când se lucrează cu componente complete care nu<br />

implementează nici o interfaŃă. In aceste situaŃii, şablonul Adapter este folosit Iară<br />

interfeŃe. Aceste implementări sunt însă mult mai puŃin flexibile<br />

- o interfaŃă între apelant şi Adapter şi una între Adapter şi Adaptee - interfaŃa<br />

între apelant şi Adapter permite noilor adaptori să fie mai uşor adăugaŃi în sistem pe<br />

parcursul rulării. InterfaŃa între Adapter şi Adaptee permite interfeŃelor Adaptee să fie<br />

încărcate dinamic în momentul rulării<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Bridge - cu toate că şabloanele Bridge şi Adapter sunt similare, intenŃia lor<br />

este diferită. Şablonul Bridge separă partea abstractă a unei componente <strong>de</strong><br />

implementarea acesteia, permiŃând fiecăreia să fie schimbate in<strong>de</strong>pen<strong>de</strong>nt. Şablonul<br />

Adapter permite utilizarea unui obiect altfel incompatibil<br />

60


- Decorator - şablonul Adapter este folosit pentru a schimba interfaŃa unui<br />

obiect, păstrând aceeaşi funcŃionalitate. Şablonul Decorator lasă interfaŃa obiectului<br />

neschimbată, dar îi intensifică funcŃionalitatea<br />

- Proxy - atât şablonul Adapter cât şi Proxy pun la dispoziŃie o interfaŃă<br />

principală unui obiect. DiferenŃa este că interfaŃa şablonului Adapter este schimbată,<br />

în timp ce interfaŃa şablonului Proxy este aceea cu cea a obiectului<br />

- Business Delegate - acest şablon pot fi folosit ca un Proxy. El poate opera ca<br />

un Adapter pentru sisteme altfel incompatibile<br />

■ Exemplu<br />

Consi<strong>de</strong>rându-se un sistem curat <strong>de</strong>ja creat, se doreşte adăugarea <strong>de</strong> noi<br />

elemente. Pentru aceasta se foloseşte şablonul Adapter:<br />

interf ace Clean { public voie! makeClean ( ) ; }<br />

elass Office irr.plements Clean { public veid<br />

makeClean() {<br />

Systern. out .println ( "Oficiu curat") ;<br />

lass Workshcp implements Clean{<br />

public voie! makeClean () {<br />

System.out.printlnŃ"3irou curat");<br />

nterface Extra exteno.s Clean; public void takeCare ( i ;<br />

lass Facility implements Extra{ public void<br />

makeCleanŃ) {<br />

System.out.println("SpaŃiu <strong>de</strong> muncă curat"<br />

public void takeCare ( ) {<br />

System.out.println("S-a realizat treaba!")<br />

class Cest {<br />

static void Jobs (Extra job) {<br />

if (job insrancecf Clean) ((Clean)job).makeClean<br />

if ((Extra) job instar.ceof Extra) Ń (Extra)j ob)<br />

.takeCare ( ) ;<br />

public static void main(Scring[] args) {<br />

Extra e =■■- nevi Facility(); Jobs (e) ;<br />

Clean ci = new Office ( ) ;<br />

Clean c.2 =■- new Worksnop ( ) ;<br />

cl.m.akeCleanO ;<br />

c2.makeClean();<br />

e.makeClean() ;


IV.2. Bridge<br />

• Cunoscut şi ca Handle / Body<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să împartă o componentă complexă în două succesiuni ierarhice separate dar<br />

asociate: funcŃionarea abstractă şi implementarea internă. Acest lucru uşurează<br />

modificarea oricărui aspect al componentei.<br />

• Introducere<br />

Pentru <strong>de</strong>zvoltarea unei liste cu lucruri ce trebuie făcute. în managerul<br />

personal <strong>de</strong> informaŃii se doreşte flexibilitate în privinŃa felului în care este<br />

reprezentată această listă utilizatorului. în plus, se vrea o posibilitate <strong>de</strong> modificare a<br />

funcŃionalităŃii <strong>de</strong> bază a listei, lăsând utilizatorilor capacitatea <strong>de</strong> a alege între o listă<br />

neordonată, o listă secvenŃială sau o listă prioritară. Pentru a introduce această<br />

caracteristică în aplicaŃie, se <strong>de</strong>zvoltă un grup <strong>de</strong> clase, fiecare conŃinând o cale<br />

specifică <strong>de</strong> afişare a listei şi <strong>de</strong> organizare a informaŃiilor. Această soluŃie <strong>de</strong>vine<br />

repe<strong>de</strong> impracticabilă, <strong>de</strong>oarece există multe modalităŃi <strong>de</strong> afişare a listei şi căi <strong>de</strong><br />

stocare a informaŃiilor listei.<br />

Este mai bine să se separe lista cu lucrurile ce trebuie făcute. Şablonul Bridge<br />

face acest lucru prin <strong>de</strong>finirea a două clase sau interfeŃe care lucrează împreună.<br />

Pentru managerul <strong>de</strong> informaŃii, acestea sunt List şi Listlmpl. Clasa List reprezintă<br />

funcŃionalitatea <strong>de</strong> afişare, ea <strong>de</strong>legând stocarea informaŃiilor articolelor listei către<br />

implementarea ei <strong>de</strong> baza, clasa Listlmpl. Beneficiul acestei soluŃii este că se pot mixa<br />

şi potrivi clasele încât să producă o mai mare funcŃionalitate.<br />

• Utilizare<br />

Şablonul Bridge se foloseşte când:<br />

- se doreşte flexibilitate între partea abstractă şi implementarea unei<br />

componente, evitându-se o relaŃie statică între cele două<br />

- orice schimbare a implementării trebuie să fie invizibilă clienŃilor<br />

- se pot crea subclase, dar se doreşte administrarea separată a celor două<br />

aspecte ale sistemului<br />

• Descriere<br />

Elementele complexe dintr-un sistem pot uneori varia atât în ceea ce priveşte<br />

funcŃionalitatea lor externă, cât şi în privinŃa implementării lor <strong>de</strong> bază. In astfel <strong>de</strong><br />

cazuri, moştenirea este o soluŃie nedorită, <strong>de</strong> vreme ce numărul claselor ce trebuie<br />

create creşte. Două reprezentări şi implementări duc la patru clase ce trebuie<br />

<strong>de</strong>zvoltate. în timp ce trei conduc la nouă clase.<br />

62


în plus. moştenirea leagă o componentă într-un mo<strong>de</strong>l static, făcând-o dificil<br />

<strong>de</strong> modificat în viitor. Schimbarea unei componente reprezintă o provocare <strong>de</strong>oarece<br />

ea tin<strong>de</strong> să varieze pe măsură ce sistemul esie <strong>de</strong>z\oltat şi utilizat. Este <strong>de</strong> preferat să<br />

se găsească o cale dinamică pentru a varia ambele aspecte ale componentei.<br />

Aici intervine şablonul Bridge. El rezolvă problema prim <strong>de</strong>scompunerea<br />

componentei în cele doua aspecte. Cu două lanŃuri <strong>de</strong> moştenire separate - unul se<br />

ocupă cu funcŃionalitatea, iar celălalt cu implementarea - este mult mai uşor să se<br />

combine elementele fiecărei părŃi. Mai mult. cerinŃele <strong>de</strong> codare a şablonului Bridge<br />

fiind scăzute, rezultă un număr mic <strong>de</strong> clase ce trebuie scrise pe măsură ce numărul<br />

variaŃiilor creşte.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Bridge este următoarea:<br />

Abstraction<br />

-Implementation implementation<br />

+void operationQ _____<br />

implementation.operalionlmpl()<br />

RefineAbstraction<br />

interface Implementation<br />

+void operationlmpl'()<br />

ConeretelmplementationA ConeretelmplementationB<br />

+void operationlmplQ +void operationlmplC<br />

Pentru implementarea şablonului Bridge se folosesc următoarele:<br />

- Abstraction - clasa ce <strong>de</strong>fineşte funcŃionarea abstractă pentru Bridge, punând<br />

la dispoziŃie comportamentul şi structura standard. ConŃine o referinŃă către o instanŃă<br />

a interfeŃei Implementation<br />

- RefineAbstraction - clasa ce extin<strong>de</strong> clasa Abstraction. conŃinând<br />

comportamente adiŃionale sau modificate<br />

- Implementation - interfaŃa ce reprezintă funcŃionalitatea <strong>de</strong> bază folosită <strong>de</strong><br />

instanŃele Abstraction<br />

- Concretelmplementation - clasa ce implementează interfaŃa Implementation.<br />

ConŃine comportamentul şi structura claselor Implementation<br />

63


• Beneficii şi inconveniente<br />

Şablonul Bridge oferă posibilitatea <strong>de</strong> a distribui obiecte cu implementare <strong>de</strong><br />

bază între multiple obiecte abstracte. Are o mare flexibilitate în ceea ce priveşte<br />

modificarea implementărilor, schimbările putând surveni iară acŃiuni necesare din<br />

partea clientului.<br />

Când se proiectează o aplicaŃie care foloseşte şablonul Bridge, este important<br />

să se cunoască exact ce responsabilităŃi aparŃin funcŃionării abstracte şi care aparŃin<br />

implementării interne. De asemenea, trebuie observat clar care este mo<strong>de</strong>lul <strong>de</strong> bază al<br />

implementării şablonului Bridge. O problemă care poate apărea în timpul utilizării<br />

şablonului Bridge este <strong>de</strong>zvoltarea implementării şablonului în jurul uneia sau mai<br />

multe variaŃii.<br />

• Variante ale şablonului<br />

Printre variantele şablonului Bridge se numără:<br />

- Automatic Bridges - unele implementări ale şablonului Bridge sunt construite<br />

astfel încât să varieze fără o acŃiune din partea utilizatorului, bazându-se în schimb pe<br />

informaŃia dată <strong>de</strong> aplicaŃie sau <strong>de</strong> platforma <strong>de</strong> operare pentru a se modifica<br />

- Shared Implementations - unele clase implementate în special cele tară stări -<br />

clase ce nu au o stare internă - pot fi distribuite între mai multe obiecte ale aplicaŃiei.<br />

In funcŃie <strong>de</strong> cât <strong>de</strong> larg sunt distribuite aceste clase pot fi implementate ca o interfaŃă<br />

- Single Implementation - uneori există doar o singură clasă implementată care<br />

serveşte mai multe clase abstracte. In acest caz, nu este necesar să se <strong>de</strong>finească o<br />

clasă <strong>de</strong> bază pentru partea <strong>de</strong> implementare a şablonului Bridge<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Adapter - şabloanele Bridge şi Adapter sunt similare ca structură, dar diferă<br />

ca intenŃie. Şablonul Bridge separă partea abstractă şi implementarea pentru a le<br />

permite să se modifice separat. Şablonul Adapter permite utilizarea unui obiect a cărui<br />

interfaŃă ar fi altminteri incompatibilă<br />

- Singleton - se foloseşte când implementarea claselor poate fi distribuită<br />

- Flyweight - când structura arborescentă <strong>de</strong>vine largă, aplicarea şablonului<br />

Flyweight poate ajuta la reducerea numărului <strong>de</strong> obiecte administrate <strong>de</strong> arbore<br />

• Exemplu<br />

Dacă se doreşte afişarea unei baze <strong>de</strong> date ce conŃine întrebări, în funcŃie <strong>de</strong><br />

dorinŃele utilizatorului, se poate utiliza şablonul Bridge:<br />

interface Question {<br />

public void nextQuest i ori ( ) ; public<br />

void newQuesrion(String q); public<br />

void displayQuesti.cn (); public voi.d<br />

displayAHQuestions ( ) ;<br />

64


class QuestionManager -.<br />

prctccred Ques:i:;:i qu-sdi;<br />

public String catilv,:;<br />

public Quest ionManager ; S ■; .-"in z ?-~do:i) {<br />

this. catalog = cazaLz::;<br />

}<br />

public voia next() { quesuii.nexLQuestion ( ) ; ■<br />

pudic void newOnc (5~ring ques~; •<br />

questDB.newQuestion'queso ; ;<br />

public void display() { questDB.displayQuestion(); }<br />

pudic void displayAll() {<br />

System.ou:.println("Question Catalog: " + catalog);<br />

questDB.displayAllQuestions() ;<br />

}<br />

i j<br />

class Quest-ioriFormat extends QuestionManager {<br />

pudic QuesrionForma~ ( String catalog) { super ( catalog) ; }<br />

pudic veid displayAllŃ) { super. displayAll (); }<br />

class JavaQuestions inplements Question {<br />

private List questions = new ArrayList();<br />

private int current = C; public JavaQuestions<br />

( ) {<br />

questions.add("Ce e Java?");<br />

questions.add("Ce e o interfaŃă?");<br />

questions.add("Ce e un fir <strong>de</strong> execuŃie?");<br />

public void nextQuestion() {<br />

if (current


■ Introducere<br />

Se doreşte modificarea managerului personal <strong>de</strong> informaŃii astfel încât el să<br />

permită utilizatorilor să administreze un proiect complex. Noile caracteristici includ<br />

<strong>de</strong>finirea proiectului ca un grup <strong>de</strong> sarcini şi subsarcini asociate, precum şi asocierea<br />

rezultatelor cu sarcinile. O cale naturală pentru în<strong>de</strong>plinirea acestui lucru este<br />

<strong>de</strong>finirea unei structuri arborescente, un<strong>de</strong> din sarcina rădăcină - care reprezintă<br />

proiectul în sine - se ramifică subproiecte. şi aşa mai <strong>de</strong>parte. Prin urmare, se<br />

<strong>de</strong>fineşte o clasa Task ce reŃine o colecŃie <strong>de</strong> alte obiecte <strong>de</strong> tip Task şi Deliverable<br />

(rezultat). De vreme ce acestea sunt legate <strong>de</strong> proiect, se <strong>de</strong>fineşte un părinte comun<br />

pentru ele - clasa Projectltem.<br />

Totuşi, ce se întâmplă dacă utilizatorii trebuie să execute o acŃiune care<br />

<strong>de</strong>pin<strong>de</strong> <strong>de</strong> tot arborele? De exemplu, un manager <strong>de</strong> proiect doreşte o estimare a<br />

timpului pentru realizarea sarcinilor şi livrarea rezultatelor pentru un anumit proiect.<br />

Pentru aceasta, trebuie scris cod pentru parcurgerea arborelui şi apelarea meto<strong>de</strong>lor<br />

potrivite la fiecare ramură. Este mult <strong>de</strong> muncă, implicând scrierea unui cod separat<br />

pentru parcurgerea arborelui, apelarea meto<strong>de</strong>lor şi colectarea rezultatelor. Având<br />

clase diferite - Task şi Deliverable - la fiecare ramură a arborelui, acestea trebuie<br />

manipulate diferit în ve<strong>de</strong>rea obŃinerii estimării timpului. Pentru un număr mare <strong>de</strong><br />

clase şi un arbore complex, codul <strong>de</strong>vine dificil <strong>de</strong> administrat.<br />

Există însă o cale mai bună <strong>de</strong> rezolvare a acestei probleme. Cu ajutorul<br />

şablonului Composite se poate folosi polimorfismul şi recursia pentru a pune la<br />

dispoziŃie o soluŃie eficientă şi simplă. Se începe prin <strong>de</strong>finirea unei meto<strong>de</strong> standard<br />

pentru toate clasele ce conŃin estimarea timpului, <strong>de</strong>numită getTimeRequired. Această<br />

metodă se <strong>de</strong>fineşte pentru interfaŃa Projectltem şi se implementează acel<br />

comportament în toate clasele care sunt tipuri ale interfeŃei Projectltem. Pentru<br />

obiectele Deliverable, metoda getTimeRequired se <strong>de</strong>fineşte astfel încât să returneze 0<br />

<strong>de</strong>oarece timpul nu este direct asociat cu un rezultat. Pentru clasa Task, se returnează<br />

un timp ce constă din timpul în care s-a efectuat sarcina plus suma apelurilor meto<strong>de</strong>i<br />

getTimeRequired pentru toate obiectele-fiu <strong>de</strong> tip Task.<br />

Folosind acest şablon, metoda getTimeRequired se <strong>de</strong>fineşte încât să calculeze<br />

automat timpul estimat fiecărei părŃi a arborelui. Se apelează metoda<br />

getTimeRequired doar pentru partea dorită a sarcinii şi codul meto<strong>de</strong>i in<strong>de</strong>plineşte<br />

funcŃia <strong>de</strong> parcurgere a arborelui şi <strong>de</strong> calcul a rezultatelor.<br />

• Utilizare<br />

Şablonul Composite se foloseşte când:<br />

- există o componentă mo<strong>de</strong>l cu o structură arborescentă<br />

- structura poate avea orice nivel <strong>de</strong> complexitate şi este dinamică<br />

- se doreşte tratarea uniformă a structuri componentelor, utilizând operaŃii<br />

comune în toată ierarhia<br />

• Descriere<br />

De multe ori se vrea <strong>de</strong>zvoltarea componentelor care urmează un mo<strong>de</strong>l parteîntreag.<br />

Acesta este un mo<strong>de</strong>l care permite tratarea unei colecŃii <strong>de</strong> obiecte i<strong>de</strong>ntice ca<br />

o entitate. Aceste structuri sunt flexibile şi uşor <strong>de</strong> folosit. Utilizatorii pot modifica<br />

structura pe măsură ce aplicaŃia rulează, adăugând sau eliminând anumite părŃi.<br />

66


Şablonul Composite suportă aceste caracteristici prin <strong>de</strong>finirea unei structuri<br />

<strong>de</strong> clase ce poate fi extinsă. Această structură este compusă dintr-o componentă <strong>de</strong><br />

bază. clase frunză şi clasa Composite. Componenta <strong>de</strong> bază conŃine mo<strong>de</strong>lul central,<br />

<strong>de</strong>finind meto<strong>de</strong>le standard sau variabilele ce vor fi folosite <strong>de</strong> toate obiectele <strong>de</strong> tip<br />

Composite. Clasele frunză conŃin comportamentul terminal. Hle reprezintă părŃi ale<br />

clasei Composite. fără a conŃine alte componente. Clasei Composite i se pot adăuga<br />

alte componente, permiŃând extin<strong>de</strong>rea structurii.<br />

Un <strong>de</strong>sen creat cu ajutorul unui instrument <strong>de</strong> editare grafică este un exemplu<br />

<strong>de</strong> şablon Composite. într-un <strong>de</strong>sen, un număr <strong>de</strong> forme elementare pot fi asociate şi<br />

tratate ca un întreg; se pot <strong>de</strong>fini <strong>de</strong> asemenea <strong>de</strong>sene care să conŃină alte <strong>de</strong>sene, sau<br />

o combinaŃie <strong>de</strong> <strong>de</strong>sene şi forme.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Composite este următoarea:<br />

Component 0..*<br />

+void operation()<br />

i i.<br />

<<br />

No<strong>de</strong><br />

Composite<br />

-Component[] components<br />

+void addComponent(Component[] c)<br />

+void operationQ +void removeComponent(Component[] c)<br />

+void operation()<br />

Şablonul Composite are trei elemente:<br />

pentru flecare copil d i n componente c.operationQ<br />

- Component - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le disponibile pentru toate părŃile<br />

structurii arborescente. Ea poate fi implementată ca o clasă abstractă atunci când<br />

trebuie pus la dispoziŃie un comportament standard pentru toate subtipurile. în mod<br />

normal, această interfaŃă nu poate fi instanŃiată; subclasele ei sau clasele care o<br />

implementează, numite şi noduri, pot fi instanŃiate şi folosite la crearea unei colecŃii<br />

sau structuri arborescente<br />

- Composite - clasa <strong>de</strong>finită <strong>de</strong> componentele pe care le conŃine. Ea susŃine un<br />

grup dinamic <strong>de</strong> obiecte Component, prin urmare are meto<strong>de</strong> pentru adăugarea şi<br />

eliminarea instanŃelor Component din colecŃia sa. Meto<strong>de</strong>le <strong>de</strong>finite în interfaŃa<br />

Component sunt implementate încât să exercite comportamentul specific pentru tipul<br />

respectiv <strong>de</strong> Composite şi să apeleze aceeaşi metodă în fiecare din nodurile sale<br />

- Leaf - clasa care implementează interfaŃa Component, conŃinând o<br />

implementare pentru fiecare din meto<strong>de</strong>le acesteia. DiferenŃa dintre o clasa Leaf şi o<br />

clasa Composite este aceea că prima nu conŃine nici o referinŃă către alte interfeŃe<br />

Component<br />

67


Beneficii şi inconveniente<br />

Şablonul Composite pune la dispoziŃie o combinaŃie puternică: flexibilitate<br />

consi<strong>de</strong>rabilă a structurii şi o interfaŃă uşor <strong>de</strong> administrat. Structura poate fi<br />

schimbată în orice moment prin apelarea meto<strong>de</strong>i potrivite pentru adăugarea sau<br />

eliminarea unei componente. Deoarece componentele unui Composite pot fi<br />

schimbate înseamnă că este posibilă şi modificarea comportamentului acestuia.<br />

Utilizarea interfeŃelor creşte şi mai mult flexibilitatea. Acestea permit<br />

construcŃia cadrelor folosind şablonul Composite şi introducerea <strong>de</strong> noi tipuri la<br />

rulare. în acelaşi timp. utilizarea interfeŃelor poate fi un inconvenient atunci când se<br />

doreşte <strong>de</strong>finirea unor atribute şi a unei implementări <strong>de</strong> bază încât fiecare nod să<br />

poată moşteni comportamentul. în aceste cazuri, interfaŃa Component trebuie <strong>de</strong>finită<br />

ca o clasă abstractă.<br />

Un alt inconvenient vine chiar din flexibilitatea şablonului - <strong>de</strong>oarece acesta<br />

este atât <strong>de</strong> dinamic, <strong>de</strong>vine uneori dificil <strong>de</strong> testat. El necesită în mod normal o<br />

strategie <strong>de</strong> testare/validare mai sofisticată, construită în jurul conceptului <strong>de</strong> ierarhie<br />

<strong>de</strong> obiecte parte-întreg. Dacă testarea <strong>de</strong>vine o problemă, cea mai bună rezolvare este<br />

introducerea testării în cadrul clasei Composite.<br />

• Variante ale şablonului<br />

Unele variante ale şablonului Composite includ:<br />

- The Root No<strong>de</strong> - pentru creşterea administrării în cadrul sistemului, unele<br />

implementări ale şablonului Composite <strong>de</strong>finesc un obiect distinct care se comportă<br />

ca o bază pentru întreaga ierarhie <strong>de</strong> obiecte. Dacă obiectul-rădăcină este reprezentat<br />

printr-o clasă separată, el poate fi implementat ca un Singleton. sau accesul către el se<br />

poate face cu ajutorul unui Singleton<br />

- Rule-based Branching - pentru structuri Composite mai complexe, în special<br />

pentru cele cu multiple tipuri <strong>de</strong> noduri şi ramuri, este uneori necesară impunerea <strong>de</strong><br />

reguli privind cum şi când anumite tipuri <strong>de</strong> noduri pot fi unite cu anumite tipuri <strong>de</strong><br />

ramuri<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Chain of Responsibility - este utilizat împreună cu şablonul Composite atunci<br />

când meto<strong>de</strong>le trebuie propagate în arbore <strong>de</strong> la frunze către ramuri<br />

- Flyweight - când structura arborescentă <strong>de</strong>vine largă, prin aplicarea acestui<br />

şablon se poate reduce numărul <strong>de</strong> obiecte administrate <strong>de</strong> arbore<br />

- Iterator - este folosit împreună cu şablonul Composite pentru a încapsula<br />

parcurgerea arborelui, care altfel ar putea <strong>de</strong>veni complicată<br />

- Visitor - folosit împreună cu şablonul Composite pentru centralizarea<br />

comportamentului care altfel ar trebui împărŃit între clasele frunză şi ramuri<br />

- Composite View - acest şablon <strong>de</strong>scrie cum o ve<strong>de</strong>re poate fi compusă din<br />

mai multe ve<strong>de</strong>ri, şi aşa mai <strong>de</strong>parte<br />

68


• Exemplu<br />

Putem consi<strong>de</strong>ra o structură arborescentă <strong>de</strong> forma următoare: un manager<br />

general are un număr <strong>de</strong> angajaŃi şi unii dintre aceştia sunt la rândul lor manageri care<br />

au un număr <strong>de</strong> angajaŃi:<br />

class Enployee {<br />

St ring nane;<br />

doucle salary;<br />

Emp]oyee(String n, double s){<br />

nane - r:;<br />

salary = s;<br />

}<br />

String getName() { return name; }<br />

double getSalary() { return salary; }<br />

public String toString() { return "Emplcyee " + name; } }<br />

class Manager (<br />

Manager mgr;<br />

Enployee[] ely;<br />

String <strong>de</strong>pt;<br />

Manager(Manager mgr,Enployee[] e, String d ) {<br />

this(e, d);<br />

this.ngr = mgr; }<br />

Manager(Employee[] e, String d) {<br />

ely = e;<br />

<strong>de</strong>pt —a;<br />

String getDeptŃ) { return <strong>de</strong>pt; }<br />

Manager getManager() { return mgr; }<br />

Employee[] getEmployee() { return ely; }<br />

public String toString() { return <strong>de</strong>pt + " manager"; }<br />

IV.4. Decorator<br />

• Cunoscut şi ca Wrapper<br />

• ProprietăŃi<br />

Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să pună la dispoziŃie o cale flexibilă <strong>de</strong> adăugare şi eliminare a funcŃionalităŃii<br />

componentelor fără a le schimba infăŃişarea externă sau funcŃia.<br />

69


Introducere<br />

Şablonul Composite <strong>de</strong>scris anterior adaugă managerului personal <strong>de</strong><br />

informaŃii funcŃionalitate, prin intermediul unei ierarhii <strong>de</strong> obiecte Task şi<br />

Deliverable. Toate clasele implementau interfaŃa Projectltem. care le i<strong>de</strong>ntifica ca<br />

aparŃinând unui proiect. Dacă însă se doreşte extin<strong>de</strong>rea capacităŃilor <strong>de</strong> bază ale<br />

claselor Task şi Deliverable, adăugând caracteristici în plus, cum ar fi următoarele?<br />

- articole <strong>de</strong>pen<strong>de</strong>nte - o interfaŃă Projectltem care <strong>de</strong>pin<strong>de</strong> <strong>de</strong> un alt obiect<br />

Task sau Deliverable pentru se realiza<br />

- suport <strong>de</strong> documente - un obiect Task sau Deliverable care face referinŃe<br />

către documentaŃii adiŃionale<br />

Dacă se adaugă aceste caracteristici folosind subclase, trebuie să se codifice o<br />

multitudine <strong>de</strong> clase. De exemplu, pentru a face doar obiectele Deliverable să suporte<br />

aceste caracteristici, trebuie scrise patru clase: Deliverable, Depen<strong>de</strong>ntDeliverable,<br />

SupportedDeliverable şi SupportedDepen<strong>de</strong>ntDeliverable. în faŃa acestui<br />

inconvenient, compunerea obiectelor poate fi consi<strong>de</strong>rată în ve<strong>de</strong>rea adăugării noilor<br />

funcŃionalităŃi. însă se poate ajunge la cod duplicat în mai multe locaŃii. în cel mai<br />

bun caz, se creşte doar complexitatea codului.<br />

Dacă, în schimb, se scriu clase care să aibă capacităŃi plug-in? Se creează clase<br />

<strong>de</strong>pen<strong>de</strong>nte care pot fi ataşate oricărei interfeŃe Projectltem pentru a se extin<strong>de</strong><br />

funcŃionalitatea <strong>de</strong> bază. De exemplu, se <strong>de</strong>finesc clasele Depen<strong>de</strong>ntProjectltem şi<br />

SupportedProjectltem. Fiecare clasă conŃine doar codul necesar capacităŃii sale<br />

opŃionale, precum şi o referinŃă către interfaŃa Projectltem reală pe care o extin<strong>de</strong>.<br />

Acest lucru înseamnă mai puŃin cod <strong>de</strong> întreŃinut şi libertatea <strong>de</strong> a folosi orice<br />

combinaŃie a acestor clase <strong>de</strong>pen<strong>de</strong>nte pentru a adăuga noi grupuri <strong>de</strong> capacităŃi.<br />

• Utilizare<br />

Şablonul Decorator se foloseşte când:<br />

- se doreşte efectuarea <strong>de</strong> schimbări dinamice care să fie transparente<br />

utilizatorilor, fără restricŃiile impuse <strong>de</strong> subclasare<br />

- capacităŃile componentelor pot fi adăugate sau eliminate pe măsură ce<br />

sistemul rulează<br />

- există un număr <strong>de</strong> caracteristici in<strong>de</strong>pen<strong>de</strong>nte care trebuie aplicate dinamic<br />

şi care pot fi folosite în orice combinaŃie<br />

• Descriere<br />

Unele obiecte au o funcŃionalitate complexă şi/sau o structură care poate fi<br />

adăugată sau eliminată. Şablonul Decorator funcŃionează permiŃând straturilor să fie<br />

adăugate sau eliminate dintr-un obiect <strong>de</strong> bază. Fiecare strat poate conŃine<br />

comportament (meto<strong>de</strong>) şi stare (variabile).<br />

Şablonul Decorator este potrivit pentru aplicaŃii care implică supraîncărcarea<br />

ce poate fi construită dinamic. Produsele Groupware ce permit echipelor ce lucrează<br />

în reŃea să combine munca <strong>de</strong> editare a unui unic document <strong>de</strong> bază. este un exemplu.<br />

De asemenea, şablonul Decorator este potrivit pentru editoarele <strong>de</strong> imagini, precum şi<br />

pentru majoritatea aplicaŃiilor ce implică texte sau formatare <strong>de</strong> documente.<br />

70


• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Decorator este următoarea:<br />

ConcreteComponent<br />

+void operationQ<br />

interface Component<br />

+void operation(')<br />

component.operationQ<br />

Decorator<br />

-Component component<br />

+void setComponent(Component c)<br />

+void operationQ<br />

Pentru implementarea şablonului Decorator este nevoie <strong>de</strong>:<br />

ConcreteDecorator<br />

-int newAttribute<br />

+void operation()<br />

+void newOperation()<br />

- Component - reprezintă comportamentul generic al unei componente. Poate<br />

fi o clasă abstractă sau o interfaŃă<br />

- Decorator - <strong>de</strong>fineşte comportamentul standard care se aşteaptă din partea<br />

tuturor Decorator-ilor. Poate fi o clasă abstractă sau o interfaŃă. ConŃine o referinŃă<br />

către un obiect Component, care poate fi un obiect ConcreteComponent sau un alt<br />

Decorator<br />

- ConcreteDecorator - fiecare subclasă a Decorator-ului trebuie să suporte<br />

înlănŃuirea (referinŃa către o componentă, plus abilitatea <strong>de</strong> a adăuga şi elimina<br />

această referinŃă)<br />

• Beneficii şi inconveniente<br />

Şablonul Decorator oferă oportunitatea <strong>de</strong> a ajusta uşor comportamentul unui<br />

obiect în timpul rulării. In plus. codarea poate <strong>de</strong>veni mult mai uşoară, <strong>de</strong> vreme ce<br />

trebuie scrise o serie <strong>de</strong> clase, fiecare Ńintind o funcŃionalitate specifică, în loc <strong>de</strong> a<br />

coda toate comportamentele în cadrul componentei însăşi. Acest lucru face<br />

componenta mult mai uşor <strong>de</strong> extins în viitor <strong>de</strong>oarece modificările pot fi introduse<br />

codând noi clase.<br />

în funcŃie <strong>de</strong> comportamentul lor, unele straturi ale şablonului Decorator pot fi<br />

distribuite între multiple obiecte ale componentei. Astfel se reduce memoria<br />

consumată <strong>de</strong> sistem.<br />

Folosit până la extrem, şablonul Decorator produce <strong>de</strong> regulă un număr mare<br />

<strong>de</strong> straturi, adică între utilizator şi obiectul real există mai multe obiecte mici. Acest<br />

lucru are un număr <strong>de</strong> consecinŃe. Testarea codului <strong>de</strong>vine mai dificilă iar viteza <strong>de</strong><br />

operare a unui sistem se reduce daca Decorator-ul este proiectat impropriu.<br />

71


Trebuie asigurată tratarea în mod egal a obiectelor. Aceasta este importantă<br />

pentru şablonul Decorator, <strong>de</strong> vreme ce straturile obiectului stau fiecare "în faŃa"<br />

celuilalt. Dacă egalitatea este testată în cadrul aplicaŃiei, atunci trebuie scrisă o<br />

operaŃie care să i<strong>de</strong>ntifice obiectul <strong>de</strong> bază sau combinaŃia dintre acesta şi ordinul şi<br />

valorile fiecărui strat.<br />

■ Variante ale şablonului<br />

De multe ori este <strong>de</strong> dorit <strong>de</strong>zvoltarea claselor şablonului Decorator cu o<br />

referinŃă înainte şi una înapoi pentru a le face mai uşor <strong>de</strong> înlăturat în timpul rulării<br />

sistemului.<br />

Unele implementări ale şablonului nu folosesc un Decorator abstract. In mod<br />

normal, această variantă este folosita atunci când există doar o singură variaŃie<br />

posibilă a componentei.<br />

Se pot crea Decoratori suprascrişi care vor re<strong>de</strong>fmi unele părŃi ale<br />

comportamentului componentei. Acest lucru trebuie să se facă însă cu grijă <strong>de</strong>oarece<br />

componentele care se bazează pe şablonul Decorator pot manifesta comportamente<br />

imprevizibile.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Adapter - acest şablon este folosit pentru schimbarea interfeŃei asupra<br />

aceleiaşi funcŃionalităŃi. în timp ce şablonul Decorator lasă interfaŃa la fel dar schimbă<br />

funcŃionalitatea<br />

- Composite - şablonul Decorator poate fi văzut ca o versiune mai simplă a<br />

şablonului Composite; în loc <strong>de</strong> avea o colecŃie <strong>de</strong> componente, Decorator-ul<br />

păstrează o singură referinŃă către o altă componentă. Cealaltă diferenŃăă este că<br />

Decorator-ul măreşte funcŃionalitatea<br />

- Strategy - şablonul Decorator este utilizat pentru a modifica sau extin<strong>de</strong><br />

funcŃionalitatea externă a unui obiect, în timp ce şablonul Strategy modifică<br />

comportamentul intern al obiectului<br />

■ Exemplu<br />

Consi<strong>de</strong>răm o clasă care afişează un număr şi utilizăm şablonul Decorator care<br />

să adauge un text numărului respectiv:<br />

class Nuir.ber {<br />

public void prinŃ() {<br />

System, out. println (r.ew Ranaom ( ) . nextlnt Ń ) ) ;<br />

class Decorator {<br />

public Decorator() {<br />

System.out.prinŃ{"Număr aleator: " ) ;<br />

new Number() .prinŃ(} ;<br />

72


ciass Sub'\uinber exter.ds Nuiiberi<br />

public SubNumber{) {<br />

super();<br />

Systen.ont.prinŃŃ"Număr aleator: ");<br />

prinŃ();<br />

IV,5. Faca<strong>de</strong> •<br />

ProprietăŃi<br />

• Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să pună la dispoziŃie o interfaŃă simplificată unui grup <strong>de</strong> subsisteme sau unui<br />

subsistem complex.<br />

• Introducere<br />

Utilizatorii doresc să poată modifica o interfaŃă grafică pentru a o face mai<br />

atractivă sau mai uşor <strong>de</strong> utilizat. De exemplu, unii utilizatori pot avea o slăbiciune<br />

vizuală sau nu pot citi un font mic, <strong>de</strong>ci trebuie să mărească dimensiunea font-ului.<br />

ForŃând utilizatorul să treacă prin toŃi paşii setup-ului, interfaŃă grafică afişând<br />

<strong>de</strong>taliile în font-ul mic, nu este un lucru prea favorabil. Un wizard care să-i ajute pe<br />

cei cu <strong>de</strong>ficienŃe vizuale să treacă prin etapele setup-ului, este mult mai bun.<br />

Acest ajutor nu trebuie să limiteze opŃiunile <strong>de</strong> utilizare şi modificare a<br />

aplicaŃiei. Se doreşte punerea la dispoziŃie a unei modalităŃi <strong>de</strong> vizualizare specializată<br />

a sistemului, în acelaşi timp menŃinându-se toate caracteristicile. Acesta este şablonul<br />

Faca<strong>de</strong> - un wizard al sistemului.<br />

• Utilizare<br />

Şablonul Faca<strong>de</strong> se foloseşte pentru:<br />

- a face sistemele complexe mai uşor <strong>de</strong> utilizat prin intermediul unei interfeŃe<br />

simple, fără a elimina opŃiunile avansate<br />

- a reduce cuplarea dintre clienŃi şi subsisteme<br />

- a stratifica subsistemele<br />

• Descriere<br />

Multe din sistemele <strong>software</strong> mo<strong>de</strong>rne sunt foarte complexe. Şabloanele ajută<br />

la structurarea aplicaŃiilor şi la o mai bună tratare a complexităŃii. De multe ori se<br />

realizează acest lucru prin împărŃirea funcŃionalităŃii între o serie <strong>de</strong> clase mai mici.<br />

Clasele adiŃionale pot fi <strong>de</strong> asemenea produse ca rezultat al partiŃionării sistemului.<br />

Divizarea unui sistem în mai multe subsisteme ajută la tratarea mai uşoară a<br />

complexităŃii sistemului şi pune la dispoziŃie oportunitatea <strong>de</strong> împărŃire a muncii.


Separând un sistem într-un număr <strong>de</strong> clase specializate este o practică hună <strong>de</strong><br />

<strong>proiectare</strong> orientată pe obiecte. Totuşi, faptul că există un număr mare <strong>de</strong> clase în<br />

sistem, poate fi un inconvenient.<br />

ClienŃii care folosesc sistemul trebuie să lucreze cu mai multe obiecte.<br />

Utilizatorii tind să <strong>de</strong>vină confuzi când au sute <strong>de</strong> opŃiuni <strong>de</strong> configurare. Prin urmare,<br />

majoritatea opŃiunilor trebuie presetate. clientul urmând să aibă doar câteva opŃiuni <strong>de</strong><br />

bază <strong>de</strong> configurat. Şablonul Faca<strong>de</strong> pune la dispoziŃie aceste opŃiuni şi poate<br />

<strong>de</strong>termina ce subsisteme trebuie apelate.<br />

în mod normal. Faca<strong>de</strong> va <strong>de</strong>lega majoritatea muncii către subsisteme, dar<br />

poate în<strong>de</strong>plini anumite atribuŃiuni el însuşi. IntenŃia lui este <strong>de</strong> realiza o interfaŃă<br />

simplă cu un set <strong>de</strong> sisteme, dar clienŃii care doresc opŃiunile mai avansate pot<br />

interacŃiona cu subsistemele.<br />

• Implementare<br />

Diagrama <strong>de</strong> obiecte a şablonului Faca<strong>de</strong> este următoarea:<br />

:Subsystem<br />

:Faca<strong>de</strong> :Faca<strong>de</strong><br />

:Subsystem :Subsvstem :Subsystem<br />

:Subsystem<br />

Pentru implementarea şablonului Faca<strong>de</strong> se folosesc următoarele:<br />

- Faca<strong>de</strong> - clasa pe care o folosesc clienŃii. Cunoaşte subsistemele pe care le<br />

utilizează şi responsabilităŃile acestora. în mod normal, toate cerinŃele clientului vor fi<br />

trimise către subsistemul cel mai potrivit<br />

- Subsystem - set <strong>de</strong> clase care poate fi folosit direct <strong>de</strong> clienŃi sau care poate<br />

în<strong>de</strong>plini munca trimisă către el <strong>de</strong> Faca<strong>de</strong>. Pentru subsistem. Faca<strong>de</strong> reprezintă un<br />

simplu client<br />

74


■ Beneficii şi inconveniente<br />

Beneficiul şablonul Faca<strong>de</strong> este acela că el realizează o interfaŃă simplă cu un<br />

sistem complex tară a reduce opŃiunile puse la dispoziŃie <strong>de</strong> sistem. Această interfaŃă<br />

protejează clientul <strong>de</strong> o abun<strong>de</strong>nŃă <strong>de</strong> opŃiuni.<br />

Şablonul Faca<strong>de</strong> trimite cerinŃele clientului către subsistemele care le pot<br />

rezolva. De regulă, o cerinŃă va fi trimisă către mai multe subsisteme. Deoarece<br />

clientul interacŃionează doar cu Faca<strong>de</strong>. activitatea internă a sistemului se poate<br />

schimbă. în timp ce clientul rămâne neschimbat pentru Faca<strong>de</strong>.<br />

Şablonul Faca<strong>de</strong> poate fi folosit pentru a reduce cuplarea între subsisteme.<br />

Fiecare subsistem poate avea propriul său Faca<strong>de</strong> iar alte părŃi ale sistemului folosesc<br />

Faca<strong>de</strong> pentru a comunica cu subsistemele.<br />

■ Variante ale şablonului<br />

Şablonul Faca<strong>de</strong> se poate implementa ca o interfaŃă sau o clasă abstractă. Se<br />

lasă astfel <strong>de</strong>taliile privind implementarea pe mai târziu.<br />

Mai multe şabloane Faca<strong>de</strong> pot pune la dispoziŃie diferite şabloane pentru<br />

acelaşi set <strong>de</strong> subsisteme.<br />

Şablonul Faca<strong>de</strong> este uneori variat pentru a ascun<strong>de</strong> subsistemele. Când este<br />

folosit ca o legătură între subsistemele arhitecturii, unul din scopurile sale este să<br />

reducă complexitatea interacŃiunii sistem-sistem. De exemplu, un sistem un<strong>de</strong><br />

apelurile trec printr-un Faca<strong>de</strong> central este mai uşor <strong>de</strong> administrat <strong>de</strong>cât unul cu un<br />

număr mare <strong>de</strong> clase cuplate.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Abstract Factory - acest şablon creează familii <strong>de</strong> obiecte asociate. Pentru a<br />

simplifica accesul la diferite obiecte care se creează, se poate crea <strong>de</strong> asemenea un<br />

obiect Faca<strong>de</strong><br />

- Mediator - şabloanele Mediator şi Faca<strong>de</strong> par foarte similare. DiferenŃa este<br />

în intenŃia şi implementarea lor. Mediator-ul ajută la uşurarea comunicării între<br />

componente şi a adăugării <strong>de</strong> comportamente. Faca<strong>de</strong> este doar o abstractizare a<br />

interfeŃei unuia sau mai multor subsisteme<br />

- Singleton - Faca<strong>de</strong> foloseşte şablonul Singleton pentru a garanta un singur<br />

punct <strong>de</strong> acces global la un subsistem<br />

- Session Faca<strong>de</strong> - acest şablon este un Faca<strong>de</strong> care încapsulează<br />

complexitatea lui Enterprise JavaBeans, pentru a simplifica interfaŃa acesteia cu<br />

clienŃii<br />

• Exemplu<br />

Un bun exemplu al şablonului Faca<strong>de</strong> este JDBC care este folosit pentru<br />

conexiunea la o bază <strong>de</strong> date şi pentru a manipula datele tară a expune <strong>de</strong>talii<br />

clienŃiilor:<br />

interface General { public void accessGenerai ( ) ; }<br />

interface Scecial extends General { publi.c void<br />

accessSpecial ( ) ; }<br />

75


interiace Private exLencis Genera] {<br />

r)ub] ic void accsssPnva:e ; j ;<br />

}<br />

class Generai.Tnfo inplements General<br />

cu'clic void accessGeneral() {<br />

class Soecrailnfo irnplements Speciali<br />

public void accessSpecial() { /<br />

public void accessGeneral;) {}<br />

lass Privatelnfo implements Private, Special {<br />

public voia aecessPrivate() { //... }<br />

public voia accessSpecial() { //... }<br />

public void accessGeneral() { //... }<br />

i<br />

ciass Connection {<br />

.<br />

user is unauthorized) tnrcw new Exceptiom<br />

if {user is general) return new Generallnfo();<br />

if (user is special) return new Speciallnfo();<br />

if (user is executive) return new Privatelnfoi<br />

IV.6. Flyweight<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să reducă numărul <strong>de</strong> obiecte <strong>de</strong> nivel scăzut dintr-un sistem prin intennediul<br />

distribuirii <strong>de</strong> obiecte.<br />

• Introducere<br />

Programarea orientată pe obiecte permite mai multor obiecte să existe pe<br />

perioada executării, în special dacă sunt obiecte <strong>de</strong> nivel scăzut. Se plasează astfel o<br />

incărcatură mare în memoria maşinii virtuale Java.<br />

Multe obiecte din managerul personal <strong>de</strong> informaŃii pot fi editate, <strong>de</strong>ci folosesc<br />

şablonul State pentru a <strong>de</strong>termina dacă conŃinutul articolelor va fi salvat. Fiecare din<br />

aceste articole poate avea propria sa colecŃie <strong>de</strong> obiecte State.<br />

O cale <strong>de</strong> a uşura problema <strong>de</strong> a avea mai multe obiecte, este distribuirea<br />

acestora. Multe din aceste obiecte <strong>de</strong> nivel scăzut diferă foarte puŃin. în vreme ce<br />

starea şi comportamentul lor sunt în cele mai multe cazuri i<strong>de</strong>ntice. Distribuirea<br />

instanŃelor reduce consi<strong>de</strong>rabil numărul lor, tară a se pier<strong>de</strong> ceva din funcŃionalitate.<br />

Pentru un set <strong>de</strong> obiecte, şablonul Flyweight separă acele părŃi ale obiectelor care sunt<br />

la fel, <strong>de</strong> părŃile care sunt diferite.<br />

76


• Utilizare<br />

Şablonul Flyweight se foloseşte atunci când:<br />

- aplicaŃia foloseşte mai multe obiecte i<strong>de</strong>ntice sau aproape i<strong>de</strong>ntice<br />

- pentru fiecare din obiectele aproape i<strong>de</strong>ntice, părŃile care diferă pot fi<br />

separate, permiŃând părŃii i<strong>de</strong>ntice să fie distribuită<br />

- grupuri <strong>de</strong> obiecte aproape i<strong>de</strong>ntice pot fi înlocuite <strong>de</strong> un obiect distribuit, o<br />

data ce părŃile diferite ale stării au fost eliminate<br />

- aplicaŃia trebuie să distingă între obiectele aproape i<strong>de</strong>ntice aflate în starea<br />

lor originală<br />

■ Descriere<br />

Şablonul Flyweight intenŃionează să reducă numărul obiectelor dintr-o<br />

aplicaŃie şi face aceasta prin distribuirea obiectelor. Obiectele conŃin date interne, dar<br />

datele privind contextul în care ele operează, sunt furnizate <strong>de</strong> o sursă externă. Fiecare<br />

obiect distribuit trebuie să fie pe cât <strong>de</strong> generic posibil şi in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong> context.<br />

Distribuind obiecte, şablonul Flyweight reduce semnificativ numărul acestora.<br />

Obiectul distribuit e folosit <strong>de</strong> mai mulŃi clienŃi şi se distinge clar <strong>de</strong> un obiect care nu<br />

este distribuit.<br />

Un exemplu <strong>de</strong> utilizare a şablonului Flyweight este un manager <strong>de</strong> plan.<br />

Atunci când se construieşte o interfaŃă grafică cu utilizatorul, se folosesc mai multe<br />

componente. Se utilizează prin urmare managerele <strong>de</strong> plan. în general, acestea sunt<br />

aproape i<strong>de</strong>ntice. Ele diferă doar în ceea ce priveşte componentele specifice pe care le<br />

administrează şi un anumit set <strong>de</strong> atribute. Daca se înlătură aceste componente şi<br />

atribute, fiecare instanŃă a acestor managere este i<strong>de</strong>ntică. Având un obiect distribuit<br />

pentru fiecare manager <strong>de</strong> plan. se reduce numărul total <strong>de</strong> obiecte.<br />

ClienŃii care folosesc obiectul distribuit au responsabilitatea <strong>de</strong> a pune la<br />

dispoziŃie şi/sau a calcula contextul informaŃional. InformaŃia este trimisă către<br />

obiectul distribuit atunci când este nevoie. Un Flyweight este distribuit, <strong>de</strong>ci un client<br />

nu trebuie să creeze un Flyweight direct. Insă nu toate obiectele Flyweight trebuie<br />

distribuite. Acest şablon permite distribuirea obiectelor, dar nu cere în mod expres<br />

acest lucru. El se foloseşte doar atunci când se pot i<strong>de</strong>ntifica şi extrage uşor datele<br />

externe din obiecte şi când numărul diferitelor stări este limitat.<br />

Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Flyweight este următoarea:<br />

FlyweightFactory 0.. *<br />

►<br />

interface Flyweight<br />

+Flyweight getFlyweight(Object Key) +void someOperation(Object externalState)<br />

i<br />

i<br />

Client<br />

ConcreteFIyweight<br />

+void someOperation(Object externai State)<br />

77


Pentru implementarea şablonului Flyweight este nevoie <strong>de</strong>:<br />

- Flyweight - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le pe care clienŃii le pot folosi<br />

pentru trimiterea stării interne către obiectele flyweight<br />

- ConcretcFlyweight - clasa ce implementează interfaŃa Flyweight şi abilitatea<br />

<strong>de</strong> a stoca datele interne. Datele interne trebuie să fie reprezentative pentru toate<br />

instanŃele un<strong>de</strong> este necesar Flyweight<br />

- FlyweightFactory - clasa responsabilă pentru crearea şi administrarea<br />

obiectelor Flyweight. Ea poate crea aceste obiecte la începutul aplicaŃiei sau atunci<br />

când este nevoie <strong>de</strong> ele<br />

- Client - clasa responsabilă pentru crearea şi punerea la dispoziŃie a<br />

contextului pentru obiectele flyweight. Singura cale <strong>de</strong> a obŃine o referinŃă către un<br />

obiect flyweight este prin intermediul clasei FlyweightFactory<br />

• Beneficii şi inconveniente<br />

Beneficiul evi<strong>de</strong>nt al acestui şablon este acela că reduce numărul <strong>de</strong> obiecte ce<br />

trebuie administrate. Se salvează astfel spaŃiu, atât în memorie cât şi pe dispozitivul<br />

<strong>de</strong> stocare. Cel mai mult spaŃiu se va salva atunci când contextul informaŃional pentru<br />

flyweight este compilat în loc <strong>de</strong> a fi stocat. Totuşi, acest lucru conduce şi la<br />

inconvenientul acestui şablon: rulare costisitoare.<br />

în loc <strong>de</strong> a stoca multe obiecte, clienŃii trebuie acum să calculeze contextul şi<br />

să pună rezultatul la dispoziŃia flyweight-ului. Acesta foloseşte apoi informaŃia pentru<br />

a compila funcŃii. Administrarea unui număr mai mic <strong>de</strong> obiecte duce la creşterea<br />

performanŃelor rulării dacă implementarea s-a făcut corect.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Abstract Factory - acest şablon este folosit pentru a se asigura o distribuire<br />

corectă a instanŃelor Flyweight<br />

- Composite - este <strong>de</strong> regulă folosit pentru a pune la dispoziŃie structura<br />

- State - este implementat <strong>de</strong> regulă folosind şablonul Flyweight<br />

- Strategy - este un alt şablon care poate beneficia <strong>de</strong> pe urma implementării<br />

lui ca un Flyweight<br />

• Exemplu<br />

Un exemplu al şablonului Flyweight este crearea a 1000 <strong>de</strong> cercuri folosind 6<br />

culori, ce conŃine obiectul Circle care poate fi reutilizat:<br />

class Circle {<br />

private Color color; public<br />

Circle(Color color) {<br />

this.color = color;<br />

public void draw (Graphics g, inc x, irit y, irit r) {<br />

g.setColor(color); g.drawOva1(x, y, r, r);<br />

78


dss lest extends JFra.te;<br />

private static final Coicr ^ -_■". !■ r .■= L J = i Celor, red,<br />

Color.blue, Color . ye-llcv:, Color . orange , Color.black,<br />

Color.whice i; private s':ati.c final int WIDTH = 400,<br />

HEIGHT = 400,<br />

NUMRER_OF_CIRCLES = 1000;<br />

public Tes;() {<br />

Container contentPane = gotConteniPane();<br />

JButton button = new J But tor: ( "Draw Circle"!;<br />

final JPane.l panel = nev; JPanel ( ) ;<br />

contentPane.add(panel, Bor<strong>de</strong>rlayout.CENTER);<br />

contentFane.add(button, Bor<strong>de</strong>rLayout.SOUTH);<br />

setSize(WIDTH ,HEIGHT);<br />

ser Defau.1 tClcseOperation ( JFrane . EXIT _ON_CLOSE ) ;<br />

setVisibie(true);<br />

button.addActionListener(nev; ActionLisrener() {<br />

public veid act ionPerf or.T.ed (ActionEvent event) {<br />

Graphics g = panel.getGraphics(); for (int i = 0;<br />

i < NUM3ER_OF_CIRCLES; + + i) { Circle circle = new<br />

Circle(getRandomCclor());<br />

circle . draw ( g, getRandorr.X ( ) ,<br />

ge~RandomY(), getRandomR());<br />

i /<br />

private int getRandonX{; {<br />

return (irit) (Math . random Ń ) *WIDTH ) ; }<br />

private int getRandomY() {<br />

return (int)(Math.random()*HEIGKT); }<br />

private int getRandomR() {<br />

return (int) (Math. random () "" (HEIGHT/10) ) ;<br />

private Color getRandomCo]or() {<br />

return colors[ ( int) (Math.random()*colors.length) }<br />

public static void main(String[] args) {<br />

Test test = new Test();<br />

IV.7. Half-Object Plus Protocol (HOPP)<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să pună la dispoziŃie o singură entitate care să trăiască în doua sau mai multe<br />

spaŃii <strong>de</strong> adresă.<br />

79


• Introducere<br />

O aplicaŃie Java poate împrăştia obiecte către diferite spaŃii <strong>de</strong> adresă - maşini<br />

virtuale Java multiple. Pentru unele tehnologii cum ar fi RMI. obiectele la distanŃă pot<br />

apela meto<strong>de</strong> în legătură cu obiecte care se află într-o altă maşină virtuală Java.<br />

permiŃând distribuirea stării şi comportamentului. Indiferent <strong>de</strong> tehnologia folosită,<br />

obiectele din diferitele maşini virtuale Java trebuie să comunice între ele pentru ca o<br />

aplicaŃie distribuită să poată funcŃiona. Dacă nu se realizează acest lucru, apare un<br />

eşec în comunicare.<br />

Presupunem că există maşinile A şi B, fiecare cu o maşină virtuală Java care<br />

rulează. Un obiect din maşina A are nevoie ca un obiect din maşina B să apeleze<br />

meto<strong>de</strong> asupra unui obiect din maşina virtuală Java B. Acest lucru se poate realiza<br />

prin mai multe mijloace. Maşina A poate apela meto<strong>de</strong> ale căror apeluri vor fi trimise<br />

către maşina B<br />

Dezavantajul este că toate apelurile <strong>de</strong> meto<strong>de</strong> vor fi trimise <strong>de</strong>-a lungul<br />

reŃelei, lucru nedorit. De multe ori se doreşte ca unele meto<strong>de</strong> invocate să se execute<br />

local, fără a se merge la obiectul <strong>de</strong> la distanŃă.<br />

Proxy-ul - reprezentarea locală a unui obiect la distanŃă - este consi<strong>de</strong>rat ca<br />

tăcând parte din obiectul la distanŃă. Executând meto<strong>de</strong>le local şi în cadrul maşinii<br />

virtuale Java la distanŃă, un obiect exercită comportament în multiple spaŃii <strong>de</strong> adresă.<br />

Şablonul HOPP realizează acest lucru.<br />

• Utilizare<br />

Şablonul HOPP se foloseşte când:<br />

- un obiect trebuie să fie în două spaŃii <strong>de</strong> adresă diferite şi nu poate fi împărŃit<br />

- o parte a funcŃionalităŃii trebuie executată la distanŃă dar unele meto<strong>de</strong> sunt<br />

apelate local<br />

- optimizări trebuie efectuate printr-o modalitate transparentă apelantului<br />

• Descriere<br />

AplicaŃiile distribuite sunt greu <strong>de</strong> scris. Una din problemele întâlnite este<br />

aceea că o singură entitate (obiect) trebuie să se afle în mai multe spaŃii <strong>de</strong> adresă, fie<br />

pentru că trebuie să acceseze multiple dispozitive fizice aflate pe maşini diferite, fie<br />

pentru că un obiect nu poate fi împărŃit logic.<br />

Pentru a diviza un obiect în două părŃi care să comunice apoi la distanŃă, se<br />

execută rmic împreună cu opŃiunea keepgenerated. Astfel se salvează codul sursă.<br />

Apoi. se editează sursa încât anumite meto<strong>de</strong> să nu fie trimise către obiectul la<br />

distanŃă. Din păcate, se limitează folosirea ulterioara a rmic-ului, <strong>de</strong>oarece <strong>de</strong> fiecare<br />

dată când acesta se utilizează asupra obiectului la distanŃă, trebuie făcută şi editarea<br />

manuală.<br />

SoluŃia este <strong>de</strong> a împărŃi obiectul în două şi a pune la dispoziŃie o cale <strong>de</strong><br />

comunicare între cele două jumătăŃi. Se implementează fiecare parte astfel încât să<br />

interacŃioneze cu obiectul aflat în spaŃiul său <strong>de</strong> adresă. Protocolul este responsabil<br />

pentru sincronizarea celor două jumătăŃi şi trimiterea informaŃiilor înainte şi înapoi.<br />

Aceasta se realizează prin intermediul şablonului HOPP - se creează un obiect<br />

care implementează interfaŃa necesară şi care conŃine o referinŃă către obiectul la<br />

distantă.<br />

80


Client<br />

■ Implementare<br />

Diagrama <strong>de</strong> clase a şablonului MOPP este următoarea:<br />

interfacc HOPP<br />

+void remo1eMelhod()<br />

+void local MethodQ<br />

LocalHOPP<br />

+void remoteMethodQ<br />

+void localMethodQ<br />

RemoteObjeetProxy<br />

+void remoteMethod()<br />

+void localMethod()<br />

RemoteObjeet<br />

+void remoteMethod()<br />

+void localMethod()<br />

Acest obiect există<br />

într-un spaŃiu <strong>de</strong><br />

adresă diferit<br />

Pentru implementarea şablonului HOPP este nevoie <strong>de</strong>:<br />

- HOBB - interfaŃa care <strong>de</strong>fineşte meto<strong>de</strong>le valabile clientului. Ambele părŃi<br />

ale obiectului HOPP implementează această interfaŃă<br />

- LocalHOPP - clasa care implementează interfaŃa HOPP. Unele meto<strong>de</strong> sunt<br />

executate local. în timp ce altele sunt trimise către RemoteObjeetProxy<br />

- RemoteObjeetProxy - această clasă este un Proxy la distanŃă care trimite<br />

toate cererile către cealaltă parte a obiectului aflat în celălalt spaŃiu <strong>de</strong> adresă. Acest<br />

proxy încapsulează protocolul care leagă cele două jumătăŃi ale obiectului<br />

- RemoteObjeet - această jumătate a obiectului HOPP conŃine toate meto<strong>de</strong>le<br />

ce vor fi executate la distanŃă<br />

- Client - clasa care apelează meto<strong>de</strong>le interfeŃei HOPP. Aceste apeluri ale<br />

meto<strong>de</strong>lor sunt transparente clientului, indiferent dacă se foloseşte un Proxy la<br />

distanŃă, un HOPP sau un obiect local<br />

• Beneficii şi inconveniente<br />

Beneficiul acestui şablon este acela că permite ca un obiect să ocupe două<br />

spaŃii <strong>de</strong> adresă. Pentru clienŃii care folosesc o parte a obiectului HOPP. el este<br />

transparent. ClienŃilor nu le pasă dacă un obiect se află în unul sau mai multe spaŃii <strong>de</strong><br />

adresă.<br />

Este posibilă şi ascun<strong>de</strong>rea completă a diferenŃelor. încât un client să creadă că<br />

foloseşte un obiect local, în timp ce părŃi ale acestuia se află la distanŃă. Se poate<br />

implementa şi partea opusă astfel încât un client să creadă că foloseşte un Proxy la<br />

distanŃă, când <strong>de</strong> fapt foloseşte un HOPP care conŃine un Proxy la distantă.<br />

81


Un alt mare avantaj este că acest şablon permite optimizări. Fiecare parte a<br />

obiectului HOPP poate <strong>de</strong>termina când şi cum doreşte să comunice cu cealaltă parte.<br />

Aceste strategii <strong>de</strong> comunicare duc la creşterea performanŃei prin scă<strong>de</strong>rea numărului<br />

<strong>de</strong> apeluri <strong>de</strong>-a lungul reŃelei, tară a afecta codul clientului.<br />

Inconvenientul acestui şablon este acela că o parte a funcŃionalităŃii trebuie<br />

duplicată. Acest lucru este necesar <strong>de</strong>oarece fiecare jumătate a obiectului trebuie să<br />

aibă suficientă funcŃionalitate ca să poată administra obiectele locale.<br />

• Variante ale şablonului<br />

Ambele jumătăŃi păstrează o referinŃă una către cealaltă şi trimit mesaje înainte<br />

şi înapoi. în forma clasică, doar jumătatea aflată <strong>de</strong> parte clientului are o referinŃă<br />

către cealaltă. ConsecinŃa este că se poate iniŃia comunicarea doar <strong>de</strong> către jumătatea<br />

aflată <strong>de</strong> partea clientului prin apelarea unei meto<strong>de</strong> a jumătăŃii aflate la distanŃă.<br />

Aceasta din urmă poate răspun<strong>de</strong> doar o dată la fiecare apel prin intermediul valorii pe<br />

care o returnează. Atunci când este necesar ca ambele părŃi să iniŃieze comunicarea,<br />

fiecare trebuie să conŃine o referinŃă către cealaltă.<br />

O altă varianta este SHOPP - Smart HOPP. In cadrul acestei implementări,<br />

partea locală a obiectului HOPP îşi poate alege duplicatul pe baza unor strategii <strong>de</strong><br />

conectare. Aceasta este <strong>de</strong> ajutor când. <strong>de</strong> exemplu, aplicaŃia este distribuită <strong>de</strong>-a<br />

lungul unei reŃele flexibile un<strong>de</strong> maşinile vin şi pleacă.<br />

In versiunea Asymmetric HOPP, cele doua jumătăŃi nu trebuie să<br />

implementeze neapărat aceeaşi interfaŃă. Partea la distanŃă poate pune la dispoziŃie un<br />

nou proxy pe care cealaltă parte să-1 folosească. Noul proxy poate conŃine optimizări<br />

sau poate fi un proxy pentru un obiect la distanŃă diferit.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Mediator - obiectele ce trebuie mediate sunt distribuite către multiple spaŃii<br />

<strong>de</strong> adresă. Mediator-ul poate folosi şablonul HOPP pentru a uşura comunicarea<br />

- Proxy - şablonul HOPP foloseşte şablonul Proxy pentru comunicarea<br />

transparentă între cele două jumătăŃi<br />

• Exemplu<br />

Consi<strong>de</strong>rându-se un calendar, acesta se păstrează într-un singur loc dar trebuie<br />

să fie disponibil oriun<strong>de</strong>. Pentru aceasta este nevoie <strong>de</strong> o interfaŃă Calendar care să<br />

<strong>de</strong>scrie meto<strong>de</strong>le disponibile la distanŃă, <strong>de</strong> o clasă Calendarlmpl ce conŃine<br />

implementările meto<strong>de</strong>lor la distanŃă şi <strong>de</strong> o clasă CalendarHopp care să poată rula<br />

local ceea ce în mod normal ar fi meto<strong>de</strong> la distanŃă:<br />

public class CalendarHO?? implements Calendar, java.io.Serializable {<br />

private static final String PROTOCOL = "rmi://"; private static<br />

final String REMOTE_SERVICE = "/calenaarimpl"; private staric<br />

final String HOPP_SERVICE = "calendar"; private static final<br />

Striric private Calendar calendar; private String host; public<br />

CalendarHOPP() {<br />

t h i s(DE FAULT HOS L) ;<br />

82


public CalendarHOPF(String host) {<br />

t r v {<br />

this.host - nost;<br />

String uri = PROTOCOL ^ host I REMOTE SERVICE;<br />

calendar = (Calendar)Naming.lookup(uri);<br />

Kaming.rebind(HOPP_SERVICE, triis);<br />

catcn (Exception exc) {<br />

System.err.println("Erroare !" - exc);<br />

}<br />

oublic String getHost() { return host; ;<br />

pudic ArrayList getAppointrrients (Date date) throws<br />

RemoteException { Return<br />

calendar.getAppointnents(date);<br />

public void addAppcintment(Appointment appointment, Date date<br />

throws Rem.oteException {<br />

calendar.addAppointment(appointment, date);<br />

IV.8. Proxy<br />

• Cunoscut şi ca Surrogate<br />

• ProprietăŃi<br />

• Scop<br />

- Tip: structural<br />

- Nivel: componentă<br />

Să pună la dispoziŃie o reprezentare a unui alt obiect, pe motive <strong>de</strong> acces,<br />

viteză sau securitate.<br />

• Introducere<br />

Pe măsură ce managerul personal <strong>de</strong> informaŃii se <strong>de</strong>zvoltă, el trebuie să<br />

administreze din ce în ce mai multe date. El conŃine adresele a numeroase persoane,<br />

inclusiv informaŃii <strong>de</strong>spre familiile acestora, hobby-uri. etc. La început numărul<br />

contactelor a fost mic, dar acum a ajuns <strong>de</strong> ordinul miilor.<br />

De multe ori. managerul <strong>de</strong> informaŃii este folosit doar pentru a schimba<br />

<strong>de</strong>taliile unei întâlniri sau pentru introducerea unei note. Prin urmare, vizualizarea<br />

cărŃii <strong>de</strong> adrese <strong>de</strong> fiecare dată când se utilizează managerul, <strong>de</strong>vine inutilă şi<br />

enervantă. Doar <strong>de</strong>schi<strong>de</strong>rea acesteia este o operaŃie costisitoare care duce la<br />

amânarea activităŃilor care nu necesită utilizarea ei.<br />

Pe un utilizator însă nu îl interesează acest fapt - el vrea doar să aibă la<br />

dispoziŃie cartea <strong>de</strong> adrese atunci când are nevoie <strong>de</strong> ea. Dar atunci când o foloseşte,<br />

nu are mereu nevoie <strong>de</strong> toate informaŃiile din ea. De exemplu, se doreşte doar<br />

cunoaşterea numărului total <strong>de</strong> contacte sau adăugarea unuia nou, fără a fi necesară<br />

observarea sau editarea întregii cărŃi <strong>de</strong> adrese.<br />

83


SoluŃia este un obiect placehol<strong>de</strong>r care să pună la dispoziŃie o interfaŃă cu<br />

cartea <strong>de</strong> adrese sau cu o parte a acesteia. Acest obiect arată asemănător cu cartea <strong>de</strong><br />

adrese, dar nu implică şi rularea acesteia. Totuşi, când este nevoie ca întreaga carte <strong>de</strong><br />

adrese să efectueze o sarcină cum ar fi modificarea adresei unui coleg, obiectul<br />

placehol<strong>de</strong>r creează a<strong>de</strong>vărata carte <strong>de</strong> adrese pentru a efectua sarcina respectivă.<br />

Acest obiect placehol<strong>de</strong>r este un Proxy.<br />

■ Utilizare<br />

- Remote Proxy (proxy la distanŃă) - se foloseşte atunci când se doreşte o<br />

reprezentare locală pentru un obiect într-un alt spaŃiu <strong>de</strong> adresă<br />

- Virtual Proxy (proxy virtual) - amână crearea obiectelor costisitoare<br />

- Protection Proxy (proxy <strong>de</strong> protecŃie) - <strong>de</strong>termină drepturile <strong>de</strong> acces la<br />

obiectul real<br />

• Descriere<br />

Un proxy este o reprezentare pentru un alt obiect. Pentru a putea face capabil<br />

proxy-ul să reprezinte obiectul real, el trebuie să implementeze aceeaşi interfaŃă ca şi<br />

obiectul real. Mai mult. proxy-ul păstrează o referinŃă către obiectul real. referinŃă <strong>de</strong><br />

care are nevoie pentru a apela meto<strong>de</strong> asupra obiectului real atunci când este necesar.<br />

ClienŃii vor interacŃiona cu proxy-ul. dar acesta poate <strong>de</strong>lega executarea către obiectul<br />

real. Cu toate că implementează aceeaşi interfaŃă ca şi obiectul real, proxy-ul poate<br />

efectua sarcini pe care obiectul real nu le poate face. cum ar fi comunicarea la distanŃă<br />

sau securitatea.<br />

Proxy-ul este un fel <strong>de</strong> suplinitor pentru obiectul real. El poate fi comparat cu<br />

sistemul <strong>de</strong> filmare a cascadoriilor periculoase pentru un film. Proxy-ul este dublura<br />

obiectului real - starul filmului. în timpul cascadoriei periculoase, proxy-ul este cel<br />

care sare din avion în locul obiectului real. Deoarece implementează aceeaşi interfaŃa<br />

ca şi obiectul real. audienŃa nu poate face diferenŃa şi cre<strong>de</strong> ca obiectul real este cel<br />

care a sărit. Dar atunci când camera se apropie, proxy-ul apelează obiectul real care<br />

preia efectuarea acŃiunii.<br />

• Implementare<br />

Diagrama <strong>de</strong> clase a şablonului Proxy este următoarea:<br />

interface Service<br />

ServiceProxv Servicelmpl<br />

84


Pentru implementarea şablonului Proxy se folosesc următoarele:<br />

- Service - interfaŃa folosită atât <strong>de</strong> proxy. cât şi <strong>de</strong> obiectul real<br />

- ServiceProxy - clasa ce implementează interfaŃa Service şi trimite apelurile<br />

meto<strong>de</strong>lor către obiectul real - Servicelmpl - atunci când este cazul<br />

- Servicelmpl - implementarea completă şi reală a interfeŃei. Acesta este<br />

obiectul reprezentat <strong>de</strong> proxy.<br />

• Beneficii şi inconveniente<br />

ConsecinŃele acestui şablon variază consi<strong>de</strong>rabil în funcŃie <strong>de</strong> tipul specific <strong>de</strong><br />

proxy folosit. Beneficiul proxy-ul la distanŃă este acela că se poate ascun<strong>de</strong> reŃeaua <strong>de</strong><br />

client. Clientul va cre<strong>de</strong> că un obiect local efectuează munca, când <strong>de</strong> fapt acesta<br />

trimite o cerere prin reŃea pentru a se efectua acŃiunea respectivă. Inconvenientul ar fi<br />

timpul mai lung <strong>de</strong> realizare a cerinŃelor, având în ve<strong>de</strong>re comportamentul reŃelei.<br />

Marele beneficiu al proxy-ul virtual este acela că se interacŃionează cu el, fără<br />

a crea obiectul real înainte <strong>de</strong> a avea nevoie <strong>de</strong> el. In plus, el poate efectua unele<br />

optimizări în ceea ce priveşte când şi cum să creeze obiectul real.<br />

Beneficiul proxy-ul <strong>de</strong> protecŃie este acela că permite controlul accesului.<br />

• Variante ale şablonului<br />

O variantă a acestui şablon este atunci când proxy-ul nu trebuie să cunoască<br />

obiectul real <strong>de</strong>cât prin intermediul interfeŃei. Creşte astfel flexibilitatea, dar acest<br />

lucru funcŃionează doar dacă proxy-ul nu este responsabil pentru crearea şi/sau<br />

distrugerea obiectului real.<br />

• Şabloane asociate<br />

Printre şabloanele asociate se află:<br />

- Adapter - pune la dispoziŃie o interfaŃă către un obiect specific, aşa cum face<br />

şi şablonul Proxy. Totuşi, Proxy-ul are aceeaşi interfaŃă ca şi obiectul. în timp ce<br />

Adapter-ul are o interfaŃă diferită<br />

- HOPP - poate folosi şablonul Proxy pentru comunicarea între două jumătăŃi<br />

distribuite ale lui<br />

- Business Delegate - acest şablon poate fi folosit ca un proxy<br />

• Exemplu<br />

Atunci când se încarcă o imagine mare, se doreşte crearea unor obiecte<br />

luminoase până când imaginea a fost încărcată complet. Pentru aceasta se poate utiliza<br />

şablonul Proxy:<br />

abstract class Graphic {<br />

public abstract voia load();<br />

public abstract void draw();<br />

85


la.ss Jmage extends Graphic{<br />

public voici l o a d ( ) ■ /<br />

public void draw() { /,<br />

lass InaFroxy extends Graphic {<br />

public void ]oadŃ) {<br />

if (irr.age -- nuli) {<br />

irr.age = r:cw Image ( f iî ename<br />

puoli.c void draw() { //...<br />

86


V. Concluzii<br />

Şabloanele ajută la <strong>de</strong>zvoltarea proiectelor <strong>software</strong> complexe, recurgându-se<br />

<strong>de</strong> foarte multe ori la soluŃii aplicate în trecut. Fiecare şablon se ocupă cu o problemă<br />

<strong>de</strong> <strong>de</strong>sign sau o implementare a unui sistem <strong>software</strong> specifică. Şabloanele pot fi<br />

folosite pentru construirea <strong>de</strong> arhitecturi <strong>software</strong> având anumite proprietăŃi.<br />

Programarea orientată pe obiecte este grea; programarea pe obiecte folosind cod<br />

reutilizabil este şi mai grea. Utilizatorii experimentaŃi realizează totuşi un <strong>de</strong>sign<br />

foarte bun şi asta pentru că ştiu faptul că nu mereu trebuie rezolvate problemele <strong>de</strong> la<br />

început. Ei reutilizează soluŃii obŃiinute anterior, şabloanele ajutând astfel la crearea<br />

unui <strong>de</strong>sign <strong>de</strong> <strong>software</strong> flexibil, uşor <strong>de</strong> întreŃinut şi <strong>de</strong> reutilizat.<br />

90


Bibliografie<br />

1. Stelting Stephen, Maassen Olav - Applied Java Patterns<br />

2. Cooper James W. - The Design Patterns Java Companion<br />

3. www.javacamp.org<br />

4. www.dofactory.com<br />

5. www.wikipedia.org<br />

91

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!