Sunteți pe pagina 1din 38

8 abloane de proiectare (Design patterns)

n domeniul proiectrii software exist soluii reutilizabile pentru problemele ce apar mai des. Un ablon de proiectare nu este un element de proiectare aflat ntr -o form final, direct transformabil n cod, ci doar o soluie pentru o anumit problem, soluie care, n timp, s-a dovedit folositoare n situaii asemntoare. abloanele de proiectare orientate obiect conin clase, relaiile i interaciunile dintre ele. Clasele coninute nu sunt ntr-o form final, structurile acestora putndu-se extinde cu elementele specifice fiecrui proiect. Algoritmii nu sunt considerai ca fiind abloane de proiectare deoarece ei rezolv probleme de implementare. Folosirea abloanelor de proiectare poate duce la creterea att a vitezei de dezvoltare a software-ului, ct i a calitii acestuia, prin utilizarea unor soluii testate, care iau dovedit eficacitatea. Proiectarea software-ului presupune luarea unor decizii a cror corectitudine se dovedete mai trziu, la partea de implementare. Reutilizarea unor abloane de proiectare ajut la prevenirea unor probleme majore i mbuntete claritatea codului pentru programatorii i arhitecii familiari cu aceste abloane. Reutilizarea abloanelor de proiectare este diferit de reutilizarea codului. Reutilizarea abloanelor de proiectare este practic o reutilizare de idei i nu de componente. n domeniul transformrii celor mai utilizate abloane de proiectare n componente se vorbete de o rat de succes de dou treimi (Meyer i Arnout). Nu orice ablon software este un ablon de proiectare. abloanele de proiectare privesc doar uurarea muncii de proiectare a aplicaiilor software. De exemplu, mai exist n domeniul software aa numitele abloane arhitecturale (architectural patterns), ce descriu, aa cum le sugereaz i denumirea, soluiile unor probleme de arhitectur software. abloanele de proiectare pot fi grupate n mai multe categorii: abloane creaionale (creational patterns); o singleton; o builder (constructor); o metod factory; o clas abstract factory; o prototip; abloane structurale (structural patterns); o adaptor; o compozit; o facade; o proxy; abloane de comportament (behavioral patterns) o observer; o strategy; o command; o iterator; o memento; o visitor; o mediator; o lan de responsabiliti (chain of responsability) Pentru exemplificare vom crea n NetBeans dou proiecte: un proiect UML Java platform Model i un proiect Java Desktop Application. Pentru o mai bun organizare a
1

claselor vom crea n ambele proiecte pachetele surs: sabloane_creationale, sabloane_structurale i sabloane_comportamentale. n proiectul UML crem o diagram de clase i dm n spaiul alb al acesteia click dreapta i Apply Design Pattern.... Dac un ablon nu presupune prea multe clase i dorim s introducem ablonul direct n model fr s l vizualizm ntr-o clas de diagrame putem da click dreapta pe nodul Model i vom gsi aceeai opiune Apply Design Pattern.... Wizardul ce se deschide ne d posibilitatea s introducem din proiectul GoF Design Patterns n propriul proiect UML principalele abloane de proiectare din literatura de specialitate (GoF vine de la Gang of Four, autorii Design Patterns: Elements of Reusable Object-Oriented Software, o carte de referin n literatura de specialitate). Clasele proiectului UML pot fi generate automat n proiectul Java de la opiunea Generate Code (click dreapta pe clasa UML).

8.1 abloane creaionale


abloanele creaionale sunt utilizate de obicei pentru a separa crearea obiectelor de utilizarea lor. Scopul principal al unui astfel de demers este de a permite introducerea n sistem a noilor tipuri derivate fr a fi necesare schimbri asupra codului ce folosete clasele de baz.

8.1.1 ablonul Singleton


Singleton este un ablon folosit pentru a restriciona instanierea unei clase la un singur obiect. Acest concept este uneori generalizat pentru a restriciona instanierea la un anumit numr de obiecte. ablonul singleton se implementeaz prin crearea unei singure clase ce conine o asociere reflexiv (unul din propriile atribute este tot de tipul clasei). Elementul cheie al acestui ablon este faptul c atributul ce are chiar tipul clasei este de tip static. Modificatorul static folosit la declararea unui atribut sau la declararea unei metode arat apartenena membrului respectiv la clas i nu la o instan a ei (la un obiect). n cazul unui atribut static, ca n exemplul ablonului singleton, se aloc memorie o singur dat, la prima initializare a clasei. La urmatoarele instanieri ale clasei nu se mai aloc memorie pentru un atribut static, dar toate obiectele din acea clas pot accesa aceeai variabil static, aflat n aceeai zon de memorie. Pe lng cele specificate mai sus, o clas singleton mai poate conine atribute i operaii specifice domeniului n care este utilizat. ablonul singleton prevede i existena unui constructor privat (dar acest constructor nu este definit i n ablonul prestabilit din NetBeans). Dac acest constructor nu ar fi privat clasa ar putea fi instaniat de mai multe ori i nu ar mai iei un singleton. Neexistnd constructorul, instana unic se obine cu o metod static denumit n continuare instance( ) (tot un fel de metod get). Aceast metod fiind static poate fi apelat cu sintaxa:
Obiect_returnat = clas.metod_static();

i ea ne va returna ntotdeuna obiectul unic instaniat (atributul static de acelai tip cu clasa n care este inclus).

Fig. 8.1 Reprezentarea unei clase singleton Instana unic poate fi creat:

1) implicit la definirea acestui element (o instaniere nu tocmai lene, mai degrab grbit i risipitoare), caz n care metoda instance( ) trebuie doar s returneze o referin la acest obiect:
public static Singleton instance() { return uniqueInstance; }

2) explicit n metoda static instance( ), dac o astfel de instan nu exist deja (aceast modalitate de instaniere este denumit instaniere lene).
public static Singleton instance () { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; }

Putem testa clasa Singleton la crearea a dou obiecte: marie i aceeasiMarie.


private sabloane_creationale.Singleton marie; private sabloane_creationale.Singleton aceeasiMarie; marie = sabloane_creationale.Singleton.instance(); marie.setSingletonData(3); String s = new Integer(marie.getSingletonData()).toString(); System.out.println("Atributul singletonData primeste valoarea " + s); aceeasiMarie = sabloane_creationale.Singleton.instance(); String s = new Integer(aceeasiMarie.getSingletonData()).toString(); System.out.println("Atributul singletonData avea deja valoarea " + s);

La lansarea codului de mai sus descoperim c, indiferent de ceea ce se spune aceeasiMarie are aceeai plarie (pardon ... aceeai valoare a atributului singletonData) i asta pentru c este aceeai marie (... acelai obiect uniqueInstance). Exemple de utilizare a ablonului singleton: - clasa user ntr-o aplicaie n care se dorete gestiunea unitar a drepturilor unui utilizator logat; - clasa destinat conexiunii cu baza de date atunci cnd se dorete ca aplicaia s foloseasc la un moment dat o singur baz de date. Pot exista i versiuni ale ablonului singleton, cele n care se limiteaz instanierea unei clase nu doar la o instan, ci la un numr finit de instane (de preferat nu numr mic). De exemplu, ntr-un joc de ah clasa juctor ar trebui s fie instaniat numai de dou ori. Soluia n acest caz presupune: - un constructor privat; - dou atribute statice de tipul clasei (uniqueWhite i uniqueBlack); - dou metode statice care s returneze cele dou instane unice (getUniqueWhite i getUniqueBlack).

Fig. 8.2 Clasa singleton Player ntr-un joc de ah Metodele statice din acest exemplu ar trebui s se asigure mai nti c exist instanele statice corespunztoare i apoi s le iniializeze, adic s le dea o nuan de alb sau de negru:
public Player getUniqueWhite() { if (uniqueWhite == null) { uniqueWhite = new Player(); color = "White"; } return uniqueWhite; }

Observaie: n exemplul de mai sus nici nu este nevoie de o operaie setColor, deoarece culoarea este stabilit doar la instanierea juctorului i nemodificat pe parcursul jocului. NetBeans ne d posibiliatea s crem propriile abloane de proiectare pe lng cele prestabilite folosind opiunea Window\Other\UML Design Center. Aici putem crea un nou proiect cu abloane, denumit eventual MyPatterns. n acest proiect putem specifica propriul singleton crend urmtoarea diagram de clase:

Fig. 8.3 Diagrama de clase necesar crerii propriului singleton

8.1.2 Metod factory


Termenul factory (fabric) este utilizat n acest context pentru a arta locul destinat construirii de obiecte. Fr a utiliza astfel de fabrici dezvoltatorii ar utiliza direct constructorii claselor pentru a obine instane ale acestora. Cu ajutorul acestor fabrici se separ logica realizrii obiectelor de clasele acestora, n locul utilizrii constructorilor fiind folosite alte metode, denumite metode factory. Rolurile ntlnite la ablonul metod factory sunt: Produs = clasa/clasele de tipul crora obinem obiecte
5

Creator = clasa/clasele ce conin metodele Factory ablonul metod factory definete o interfa (Creator) destinat crerii unui obiect, dar las subclasele (ConcreteCreator) s decid (prin suprascriere) care clas (ConcreteProduct) va fi efectiv instaniat.

Fig. 8.4 ablonul metod factory

Fig. 8.5 Exemplu de ablon metod factory ablonul este folosit n ierarhiile de clase paralele, cnd obiectele dintr-o ierarhie creeaz obiecte corespunztoare din cealalt ierarhie. De exemplu, putem dezvolta o ierarhie de psri (gin, ra, stru), ce produc anumite tipuri de ou. Fiecrui element din ierarhia de psri i corespunde un anumit tip de ou (nu punem sraca gin s produc un ou de stru, spre bucuria ei).

n plus fa de codul generat automat pe baza diagramei de mai sus va trebui sa suprascriem metodele creazaOu din clasele Gaina i Strut, n aa fel nct s facem legtura logic dintre cele dou ierarhii de clase.
public final class gaina extends pasare { public final ou creazaOu(){ return new oudegaina(); } }

i
public final class strut extends pasare { public final ou creazaOu(){ return new oudestrut(); } }

n practic are sens s folosim ablonul cnd metodele de mai sus sunt complexe, presupun accesul la caracteristici ale mediul client i calculeaz valori pentru atributele obiectelor obinute. Clientul acestui ablon doar creaz un obiect de tipul unei anumite psri (s spunem gin) i prin utilizarea metodei creazaOu obine un obiect de tipul Oudegaina, dei nu a scris explicit n cod numele acestei clase.
public static void main(String[] args) { creationale.factory.gaina gaina; creationale.factory.ou oudeceva; gaina = new creationale.factory.gaina(); oudeceva = gaina.creazaOu(); System.out.println("A fost creat oudeceva.getClass().getSimpleName()); }

un

"

Rezultatul afiat este: A fost creat un oudegaina Metodele factory pot accepta opional parametri care definesc modul n care obiectul este creat. Astfel putem crea variante simplificate ale acestui ablon, n care utilizam o singur ierarhie de clase, cea a Produselor i o singur clas Creator cu o metod factory a crui parametru s ajute la identificarea tipului concret de produs realizat. Acest ablon poate fi implementat cu dificultate atunci cnd este folosit pentru clase ce au deja clieni. Adic dac ncepem prin aplicaie s folosim constructorul implicit de ou, e puin cam trziu s mai introducem n ecuaie i pasrea cu metoda ei factory de fcut ou (creazaOu).

8.1.3 Clas abstract factory


ablonul clas abstract factory impune existena unui nivel suplimentar de abstractizare fa de ablonul metod Factory i nu exclude acest ablon. Conform acestui ablon se creeaz o clas abstract factory ce va sta la baza mai multor clase concrete factory, deci nu putem avea versiuni simplificate ca n ablonul anterior n care s existe o singur clas Creator (factory). Clasele factory conin cte o metod factory pentru fiecare tip de obiect ce trebuie creat.

ablonul abstract factory asigur o modalitate de grupare a mai multor metode factory ce au elemente (teme) comune. Codul client lucreaz doar cu tipul abstract de factory, nedepinznd de tipurile concrete. Conform acestui ablon, sunt create obiecte concrete, dar codul client le acceseaz doar prin interfaa lor abstract. Adugarea de noi tipuri concrete sistemului se face prin modificarea codului client, n aa fel nct s foloseasc o nou clas concret factory.

Fig. 8.6 ablonul clas abstract factory ablonul clas abstract Factory este util atunci cnd o aplicaie trebuie s creeze diferite grupuri de obiecte n funcie de o anumit stare a mediului de execuie. De exemplu, o aplicaie poate fi gndit n aa fel nct s afieze diferite interfee grafice n funcie de mrimea i rezoluia ecranului. Pentru ecrane mici aplicaia poate apela la interfee grafice gndite s ncap ntr-un spaiu astfel limitat. De exemplu, textele din interfa pot fi scrise n mod abreviat i/sau cu font-uri mai mici, iar imaginile afiate ar avea un numr mai mic de pixeli i de culori. Fiecare din aceste interfee grafice urmeaz s implementeze aceeai interfa, adic sunt vizibile din cadrul aplicaiei client n mod identic. n exemplul urmtor clasa abstract InterfataGrafica are rolul de Factory i ajut la crearea de obiecte (imagine, text, liste etc.) de diferite tipuri optimizate pentru diferite ecrane. Pentru fiecare grup de ecrane se creaz clase concrete Factory: InterfataGraficaMica, InterfataGraficaMedie, InterfataGraficaMare. n aplicaia ce va folosi una din aceste interfee putem scrie:
Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension scrnsize = toolkit.getScreenSize(); int resolution = toolkit.getScreenResolution(); System.out.println ("Screen width: " + scrnsize.getWidth()); System.out.println ("Screen height: " + scrnsize.getHeight()); System.out.println ("Screen resolution: " + resolution); InterfataGrafica myGUI = null; if (resolution < 40) {myGUI = new InterfataGraficaMica();} if (resolution >= 40 && resolution<96) {myGUI = new InterfataGraficaMedie();} if (resolution >= 96) {myGUI = new InterfataGraficaMare();} System.out.println("Se foloseste o " + myGUI.getClass().getSimpleName());

8.1.4 Prototip
ablonul const n folosirea unei instane drept prototip pentru crearea (clonarea) de noi obiecte. ablonul protoype este folosit pentru: - a evita folosirea subclaselor concrete factory n aplicaiile client; - a evita crearea de obiecte n mod clasic, cu metode constructor. Pentru implementarea acestui ablon se declar o clas de baz abstract ce specific o operaie clonePrototype. Orice clas ce are nevoie de un constructor polimorfic va deriva din clasa de baz abstract i implementeaz operaia clonePrototype.

Fig. 8.7 ablonul prototip Operaia clonePrototype poate fi folosit dup crearea unei prime instane a clasei respective. A clona un obiect nseamn s se creeze un nou obiect i s i se modifice acestuia valorile atributelor cu valorile atributelor obiectului clonat. Avantajele ablonului se vd atunci cnd realizarea acestei prime instane presupune un efort deosebit de timp sau resurse, efort ce nu mai este necesar de la a doua instan. Presupunnd clonarea oiei Dolly cel mai mnemonic exemplu despre clonare:

Fig. 8.8 Exemplu de ablon prototip


9

Utilizarea ablonului de mai sus presupune implementarea metodei clonePrototype din clasa Sheep:
public Prototype clonePrototype () { Sheep clonedSheep = new Sheep(); clonedSheep.rasa = this.rasa; clonedSheep.culoare = this.culoare; clonedSheep.varsta = this.varsta; return clonedSheep; }

i apelarea acesteia din programul client:


sabloane_creationale.Sheep dolly = new sabloane_creationale.Sheep(); dolly.setRasa("Chevlot"); dolly.setCuloare("alba"); dolly.setVarsta(6); sabloane_creationale.Prototype dollysSyster = dolly.clonePrototype(); System.out.println("Rasa clonei este " + dollysSyster.getRasa()); System.out.println("Culoarea clonei este " + dollysSyster.getCuloare()); System.out.println("Varsta clonei este " + dollysSyster.getVarsta()+" ani");

8.1.5 Builder
ablonul builder ajut la abstractizarea pailor construirii unor obiecte, altfel spus a reetelor de fabricaie. Obiectele de obinut nu fac parte dintr-o anumit ierarhie de clase, dar exist constrngerea ca valorile atributelor acestora s nu aib sens dect ntr-o anumit combinaie. Fiecare combinaie de valori ale atributelor se obine cu un anumit builder (cu o anumit reet de fabricaie). Aceti builder-i sunt organizai ntr-o ierarhie de clase.

Fig. 8.9 ablonul builder Clasa director este cea care construiete efectiv produsul cu ajutorul unui builder (reete de fabricaie) pe care l conine. Metoda construct din clasa director include o secven
10

de apelri a metodelor de construire a prilor (atributelor) produselor. Cum toate produsele (obiectele) obinute sunt instane ale aceeleiai clase nseamn c toate au aceleai pri i prin urmare toate se pot obine prin respectarea aceleiai secvene de construire. Pot exista variante ale acestui ablon n care Builder este o clas abstract i nu o interfa. Motivul folosirii unei clase abstracte poate fi n acest caz agregarea n Builder a unui obiect produs protejat (protected). Cel mai reuit exemplu de utilizare a ablonului builder este cel de pe wikipedia unde clasa cu rolul product este clasa pizza, clasele cu rolurile concretebuilder sunt diferitele reete de pizza, iar clasa cu rolul director este clasa buctar (exemplul de pe wikipedia scris in C# este corect, cel n Java are lacune).

Fig. 8.10 Exemplu de ablon builder n exemplul de mai sus, clasele reet i pizza pot rmne cu codul generat automat pe baza diagramei, dar: - clasa buctar trebuie s tie ordinea n care se pregtesc diferitele pri de pizza; - clasa RetetaPizzaSalami trebuie s tie cum se pregtete fiecare parte din pizza salami.
public class Bucatar { public Pizza gateste (Reteta oRetetaDePizza) { oRetetaDePizza.pregatesteBlat(); oRetetaDePizza.pregatesteSos(); oRetetaDePizza.pregatesteContinut(); return oRetetaDePizza.getPizza(); }}

11

public class RetetaPizzaSalami extends Reteta { public void pregatesteBlat () { pizza.setBlat("subtire"); } public void pregatesteSos () { pizza.setSos("iute"); } public void pregatesteContinut () { pizza.setContinut("salam"); } }

n aplicaia client ajunge s i apelm unui buctar metoda gtete i s i spunem ce fel de pizza dorim, fr s cunoatem detaliile reetei de fabricaie.
sabloane_creationale.Bucatar popescu = new sabloane_creationale.Bucatar(); sabloane_creationale.RetetaPizzaSalami retetaPizzaSalami = new sabloane_creationale.RetetaPizzaSalami(); sabloane_creationale.Pizza pizza = popescu.gateste(retetaPizzaSalami); System.out.println("Pizza obtinuta contine "+ pizza.getContinut() + ", are blatul " + pizza.getBlat()+ " si sosul " + pizza.getSos() );

Avantajul acestui ablon const n separarea reetei de fabricaie de beneficiarul produselor obinute.

12

8.2 abloane structurale


8.2.1 Adaptor
Adaptorul (cunoscut i sub numele de wrapper) este o clas ce permite traducerea unor interfee n alte interfee. Adaptorul permite unor clase cu interfee incompatibile s interacioneze. Acest ablon este folositor atunci cnd o clas deja implementat (clasa de adaptat sau clasa furnizor) asigur funcionalitile dorite, dar nu i interfaa dorit. Adaptorul tie s rspund cel puin la interfaa dorit de client, din acest motiv clasa adaptor este utilizat n mod direct de ctre clasa client. n acelai timp adaptorul tie s utilizeze funcionalitile clasei de adaptat. n acest fel, clasa client este independent de structura interfeei de adaptat. Cu un astfel de ablon clasa client poate modifica furnizorii de funcionaliti fr s i modifice propria structur, doar utiliznd ali adaptori. Exist dou tipuri de adaptoare, n funcie de modul n care adaptorul reuete s utilizeze funcionalitile clasei de adaptat: obiect adaptor i clas adaptor.

8.2.1.1 Obiect adaptor

Fig. 8.11 ablonul obiect adaptor n diagrama de mai sus o clas Client tie s foloseasc doar clase ce implementeaz interfaa Target. Toat logica scris n clasa Client depinde de aceast interfa. Ce ne facem dac la un moment dat clasa Client trebuie s foloseasc i clase care nu au implementat interfaa Target, dar au aceeai funcionalitate dorit de clasa Client (aa cum este clasa Furnizor)? Mai sus am scris ngroat cuvntul i pentru a arta c rescrierea clasei Client este exclus, ea trebuind s poat funciona i cu vechile implementri ale interfeei Target. Soluia propus de ablonul obiect adaptor este de a crea o clas Adapter care: - s conin un atribut de tipul clasei de adaptat, clasa Furnizor; - s implementeze interfaa Target;

13

- s suprascrie metodele interfeei Target (cum ar fi metoda request), n aa fel nct la execuia acestora s se apeleze metodele instanei de tip Furnizor (de exemplu, metoda specificRequest). n metoda request a adaptorului se scrie n acest caz:
public void request () { furnizor.specificRequest(); }

Un exemplu de utilizare a ablonului object adaptor este cel n care aplicaiile client de messenger pot utiliza diferite servere de messenger. Iniial un client de messenger poate fi dezvoltat pentru un singur server, ulterior dorindu-se utilizarea i a altor servere. Figura 8.12 face referire la clasele specifice unei astfel de aplicaii iniiale n care clientul, n metoda sendText, utilizeaz metoda sendText dintr -un anumit server.

Fig. 8.12 Diagrama claselor ntr-o aplicaie de messenger Pentru utilizarea unui alt server de messenger, clasa ServerMessenger se poate specializa ntr-un adaptor ce conine ca i membru un obiect de tipul unui alt server. Metoda sendText a adaptorului suprascrie metoda sendText a serverului iniial, delegnd activitatea de realizat membrului obiect de tipul celuilalt server, mai exact folosind metoda sendMessage a acestuia.

Fig. 8.13 Aplicaie de messenger cu un object adapter


14

Un alt exemplu de utilizare a ablonului obiect adaptor este cel dintr-un sistem B2B n care aplicaia de achiziie a unui magazin tie s foloseasc iniial doar o anumit aplicaie de defacere instalat la un furnizor. n aceast form iniial a sistemului exist doar elementele din stnga ale urmtoarei diagrame:

Fig. 8.14 Aplicaie B2B cu un object adapter Clasa Achizitie depinde de interfaa IDesfacere mcar prin faptul c metoda cumpar apeleaz metoda vinde. Dac la un moment dat apare un Furnizor care are instalat o alt aplicaie, ce nu implementeaz interfaa IDesfacere, dar ajut tot la vnzarea de marf, putem crea clasa AdapteazaSale. Conform acestui ablon clasa AdapteazaSale: - conine un atribut de tipul clasei de adaptat, clasa Sale; - implementeaz interfaa IDesfacere; - suprascrie metoda vinde, n aa fel nct aceasta s apeleze metodele setCurrentProduct i sell ale obiectului de tip Sale. La codul generat pe baza diagramei anterioare am adugat un cod formatat aici cu litere ngroate pentru a nelege ce mai rmne de scris la mn din prezentul ablon.
public class Achizitie { private IDesfacere mIDesfacere; public void cumpara (String codProdus, Double cantitate, String furnizor) { //in functie de furnizor folosim anumite implementari if (furnizor.equals("furnizor1")) mIDesfacere = new Desfacere(); if (furnizor.equals("furnizor2")) mIDesfacere = new AdapteazaSale(); mIDesfacere.vinde(codProdus, cantitate); } } public interface IDesfacere { public void vinde (String codProdus, Double cantitate); }

15

public class Desfacere implements IDesfacere { public void vinde (String codProdus, Double cantitate) { System.out.println("Se foloseste clasa Desfacere pentru a cumpara produsul "+ codProdus); } } public class AdapteazaSale implements IDesfacere { private Sale mSale = new Sale(); public void vinde (String codProdus, Double cantitate) { int quantity = cantitate.intValue();//adaptam tipul parametrilor mSale.setCurrentProduct(codProdus);//lansam doua metode in loc de una mSale.sell(quantity); } } public class Sale { private String currentProduct; public void sell (int quantity) { System.out.println("Se foloseste clasa Sale pentru a cumpara produsul " + this.currentProduct); } public String getCurrentProduct () { return currentProduct; } public void setCurrentProduct (String val) { this.currentProduct = val; } }

Utilizarea ablonului presupune darea n execuie a urmtoarelor rnduri de cod:


Achizitie achizitie = new Achizitie(); achizitie.cumpara("12345", 3.14, "furnizor1"); achizitie.cumpara("56789", 999., "furnizor2");

Rezultatul afiat este:


Se foloseste clasa Desfacere pentru a cumpara produsul 12345 Se foloseste clasa Sale pentru a cumpara produsul 56789

8.2.1.2 Clas adaptoare


n ablonul anterior (obiect adaptor) se creaz un adaptor pentru fiecare clas Furnizor. ablonul clas adaptor presupune utilizarea unui singur adaptor pentru mai multe clase Furnizor. Acest tip de adaptor implementeaz toate interfeele claselor Furnizor. Cu acest ablon se poate crea i un adaptor bidirecional a dou clase/interfee.

16

Fig. 8.15 ablonul class adapter cu implementare multipl de interfee Adaptorul descris n figura 8.15 poate fi folosit att pentru o aplicaie ce depinde de ClassA, dar care dispune de ClassB, ct i invers. ablonul class adapter presupune folosirea motenirii multiple, de unde i vin i anumite dezavantaje: - nu toate mediile de programare suport complet motenirea multipl (de aceea figura 8.15 face referire la implementrile a dou interfee i nu la extinderea a dou clase); - pot apare conflicte ntre operaiile celor dou interfee cnd aceste operaii au aceeai semntur dar o semantic diferit. n figura 8.16 exemplificm o clas Adaptor ce implementeaz trei interfee: IDesfacere, ISale, IVente. Practic lum problema de la ultimul exemplu de object adapter (cea cu achiziiile ntr-un sistem B2B) i o rezolvm cu un class adapter, pentru a nelege mai bine diferenele dintre acestea. Clasa cu rolul de Client (clasa Achizitie) nu mai conine un membru ce implementeaz interfaa IDesfacere, ci conine un membru de tip Adapter, adic structura acesteia este pregtit din prima s utilizeze diferite sisteme de desfacere.

17

Fig. 8.16 Exemplu de clas adaptor


public class Achizitie { private Adaptor mAdaptor = new Adaptor(); public void furnizor) { cumpara (String codProdus, Double cantitate, String

if (furnizor.equals("furnizor1")) mAdaptor.setDesfacere(new Desfacere()); if (furnizor.equals("furnizor2")) mAdaptor.setSale(new Sale()); if (furnizor.equals("furnizor3")) mAdaptor.setVente(new Vente()); mAdaptor.vinde(codProdus, cantitate); if (furnizor.equals("furnizor1")) mAdaptor.setDesfacere(null); if (furnizor.equals("furnizor2")) mAdaptor.setSale(null); if (furnizor.equals("furnizor3")) mAdaptor.setVente(null); }

18

public Adaptor getAdaptor () { return mAdaptor; } public void setAdaptor (Adaptor val) { this.mAdaptor = val; } } public class Adaptor implements IDesfacere, ISale, IVente { private Vente mVente; private Desfacere mDesfacere; private Sale mSale; public void vinde (String codProdus, Double cantitate) { if (mDesfacere != null) mDesfacere.vinde(codProdus, cantitate); if (mSale != null) {mSale.setCurrentProduct(codProdus); mSale.sell(cantitate.intValue()); } if (mVente != null) {mVente.setProduit(codProdus); mVente.setQuantite(cantitate); mVente.vendre(); } } public void sell (int quantity) { // aici putem sa scriem un cod asemanator cu cel din metoda vinde, dar care ar fi folosit atunci cnd adaptorul este folosit prin interfata ISale } public void vendre () { // aici putem sa scriem un cod asemanator cu cel din metoda vinde, dar care ar fi folosit atunci cnd adaptorul este folosit prin interfata IVente } // si in rest set-uri si get-uri ale clasei Adapter } public class Desfacere implements IDesfacere { public void vinde (String codProdus, Double cantitate) { System.out.println("Se foloseste clasa Desfacere pentru a cumpara produsul "+ codProdus); } } public class Sale implements ISale { private String currentProduct; public void sell (int quantity) { System.out.println("Se foloseste produsul " + this.currentProduct); } public String getCurrentProduct () { return currentProduct; } clasa Sale pentru a cumpara

19

public void setCurrentProduct (String val) { this.currentProduct = val; } } public class Vente implements IVente { private String produit; private Double quantite; public void vendre () { System.out.println("Se produsul "+ produit); } foloseste clasa Vente pentru a cumpara

public String getProduit () { return produit; } public void setProduit (String val) { this.produit = val; } public Double getQuantite () { return quantite; } public void setQuantite (Double val) { this.quantite = val; } }

Utilizarea ablonului presupune darea n execuie a urmtoarelor rnduri de cod:


Achizitie achizitie = new Achizitie(); achizitie.cumpara("12345", 3.14, "furnizor1"); achizitie.cumpara("56789", 999., "furnizor2"); achizitie.cumpara("24680", 123., "furnizor3");

Rezultatul afiat este:


Se foloseste clasa Desfacere pentru a cumpara produsul 12345 Se foloseste clasa Sale pentru a cumpara produsul 56789 Se foloseste clasa Vente pentru a cumpara produsul 24680

Alte exemple de utilizare a adaptoarelor: - wrapper-ele din bazele de date federative (DB2) care fac legtur ntre baze de date eterogene; - coletele de transmis prin intermediul oficiilor potale diferite.

8.2.2 Compozit
ablonul compozit permite unui grup de obiecte s fie tratat ca un singur obiect. Cu ajutorul acestui ablon o operaie specific elementelor componente poate fi lansat i pentru un agregat, situaie n care operaia se lanseaz pentru toate elementele agregate. Una din situaiile n care ablonul compozit se face util este cea n care se gestioneaz structuri ierarhice. Diferena structural dintre noduri i frunze face ca lucrul cu structuri ierarhice s fie complex. Soluia propus de ablon este de a obine elementul

20

compozit (nodul n cazul structurilor ierarhice) din specializarea clasei destinat componentelor (frunzelor).

Fig. 8.17 ablonul compozit ablonul nu este util doar n cazul structurilor ierarhice, ci n toate relaiile de compunere n care operaiile unui grup de obiecte include operaiile unui singur obiect. Clasa destinat componentelor conine pe lng implementarea operaiilor specifice domeniului afacerii i declararea interfeei pentru accesarea i gestiunea componentelor copil (adugare, tergere, citire etc.). Clasa compozit implementeaz metodele de manipulare a componentelor copil, iar n cazul operaiilor specifice domeniului afacerii i deleg sarcinile operaiilor corespunztoare ale obiectelor copil. n exemplul urmtor este vorba de ziariti care fac parte din redacii, redacii care aparin de anumite publicaii (ziare, reviste etc.), publicaii ce aparin unor trusturi de pres. ablonul compozit ne ajut n acest caz ca o operaie specific unui ziarist (cea de a ataca) s fie lansat (de un mogul) pentru un ntreg trust, cu un efort minim, fr a apela fiecare ziarist n parte, ci apelnd doar operaia ataca a obiectului trust.

21

Fig. 8.18 ablonul compozit


public interface Componenta { public void ataca (); } public class Ziarist implements Componenta { public void ataca () { System.out.println("Hau hau!"); } } public class Grup implements Componenta { private ArrayList<Componenta> mComponenta = new ArrayList<Componenta>(); public void ataca () { for (Componenta componenta : mComponenta) { componenta.ataca(); } } public void add (Componenta c) { mComponenta.add(c); } public void remove (Componenta c) { mComponenta.remove(c); } }

Dac declaraiile de mai sus ar face parte din pachetul sabloane_structurale, intrnd n pielea unui mogul am putea utiliza codul urmtor:
sabloane_structurale.Grup trust = new sabloane_structurale.Grup(); sabloane_structurale.Grup ziar = new sabloane_structurale.Grup(); sabloane_structurale.Grup redactie = new sabloane_structurale.Grup(); sabloane_structurale.Ziarist popescu = new sabloane_structurale.Ziarist(); sabloane_structurale.Ziarist ionescu = new sabloane_structurale.Ziarist(); sabloane_structurale.Ziarist altescu = new sabloane_structurale.Ziarist(); redactie.add(popescu); redactie.add(ionescu);

22

redactie.add(altescu); ziar.add(redactie); trust.add(ziar); trust.ataca();

8.2.3 Facade (faad)


O faad este un obiect ce asigur o interfa simplificat spre un grup de clase. Cu ajutorul acestui ablon o bibliotec software devine mai uor de neles i de utilizat, reducndu-i dependena de restul codului (scade cuplarea). O faad este recomandat i atunci cnd trebuie s folosim o colecie de clase ce folosesc interfee prost proiectate sau greu de neles, n sperana c interfaa faadei va rezolva aceste probleme.

Fig. 8.19 ablonul facade

23

n exemplul din figura 8.19 cel care creaz obiectele de tip tranzacie (dintr-o interfa utilizator sau dintr-o procedur de import) nu trebuie s cunoasc detaliile faadei (claselor de contabilitate i gestiune), ci doar c o tranzacie, dup ce a fost creat, trebuie transmis faadei de tip ContabilitateSiGestiune pentru nregistrarea acesteia n contabilitate i afectarea gestiunilor corespondente:
//se creaza tranzactia cu datele din GUI/import Tranzactie tranzactie = new Tranzactie(); tranzactie.setSuma(11.); tranzactie.setTip("BUY"); //se creaza si se foloseste fatada fr s se cunoasc detaliile ei ContabilitateSiGestiune fatada = new ContabilitateSiGestiune(); fatada.setTranzactie(tranzactie); fatada.contabilizeaza();

n acest caz metoda contabilizeaza din faada ContabilitateSiGestiune include toat secvena de apelri a claselor: RegistruJurnal, CarteaMare, RegistruDeCasa, RegistruDeBanca, Stocuri.

8.2.4 Proxy
La modul general un proxy este o resurs (clas, server etc.) care funcioneaz ca o interfa pentru altceva. Un proxy nu face dect s delege aciunile mai departe unei alte clase.

Fig. 8.20 ablonul proxy Exist patru situaii n care se recomand s folosim un astfel de ablon: 1) Virtual proxy = o clas de acces ctre obiectele unei alte clase ce presupune utilizarea multor resurse; obiectul real este creat la prima cerere de acces la acesta. 2) Remote proxy = asigur o reprezentare local pentru un obiect dintr-un spaiu diferit de memorie; n RPC i CORBA o astfel de funcionalitatea o asigur un stub. 3) Protective proxy = clas de control al accesului la obiecte mai sensibile din punct de vedere al securitii. Obiectul proxy verific dac expeditorul are dreptul s transmit mesaje destinatarului.

24

4) Smart proxy = clas care nu doar transmite mai departe o operaie de realizat, ci realizeaz n plus o serie de aciuni, cum ar fi: a. numr referirile la un anumit obiect; b. ncarc obiecte persistente la prima utilizare; c. verific dac obiectul adevrat este blocat pentru alte accese (asigur prelucrri tranzacionale i diferite niveluri de izolare) Exemplificm un protective proxy:
//atat obiectul proxy cat si realSubject implementeaza aceeasi interfata public interface Subject { public void request (); } public class RealSubject implements Subject { public void request () { System.out.println(this.getClass().getSimpleName() operatia dorita!"); } } public class Proxy implements Subject { private RealSubject mRealSubject = new RealSubject(); public void request () { //daca numele utilizatorului sistemului de operare = .... if (System.getProperty("user.name").contentEquals("Florin")) { mRealSubject.request(); } else { System.out.println(this.getClass().getSimpleName() + executia operatiei dorite!"); } } }

"

executa

"

refuza

8.2.5 Decorator
ablonul decorator ofer o modalitate de a aduga comportament unor obiecte individuale fr a fi necesar crearea unei noi clase pentru a realiza acest lucru. Adugarea de noi funcionaliti obiectelor poate fi fcut conform acestui ablon n mod dinamic, n timpul execuiei programului. Soluia derivrii este i ea acceptabil n general, dar este important de tiut c nu este unica soluie de adugare a unor noi comportamente i c se pot evita ierarhii stufoase. Acest ablon adaug funcionaliti unor instane specifice ale unei clase i nu ntregii clase, permind adaptarea clasei respective, fr a crea clase derivate care s duc la ierarhii complexe. Soluia ablonului const n nglobarea uneia sau mai multor componente ntr-un obiect (cu rolul decorator), fiecare component coninnd metodele noii funcionaliti.

25

Fig. 8.21 ablonul Decorator Interfaa Component definete interfaa obiectelor ce adaug noi funcionaliti. Interfa Decorator este destinat obiectelor ce vor beneficia la run-time de noi functionaliti. Clasa ConcreteDecorator este o implementare a interfeei Decorator. Metoda addedBehavior este doar un exemplu de specializare i nu face parte din specificul ablonului, ci din contra: specificul ablonului este de aduga funcionaliti n componente concrete i nu direct prin astfel de noi metode. n exemplul urmtor vom utiliza clase abstracte n loc de interfee pentru a putea include ntr-un Decorator atribute nonstatice. El face referire la un grup de clase de control menit s gestioneze drepturile accesibile inclusiv prin interfee grafice.

Fig. 8.22 Exemplu de ablon decorator Clasa abstract GrupDrepturi are rolul de Decorator, deoarece beneficiaz de noi funcionaliti cu ajutorul coleciei de drepturi. Un Decorator concret este GrupDrepturiPentruContabili. Clasa abstract Drept are rolul de component. Clasa DreptModulTranzactie este o component concret, ce include metode pentru utilizarea tuturor drepturilor specifice unui Modul de Tranzactie.
26

8.3 abloane comportamentale


8.3.1 Mediator
De obicei o aplicaie este alctuit dintr-un numr important de clase. Cu ct sunt mai multe clase ntr-o aplicaie, problema comunicrii ntre obiecte devine mai complex, ceea ce face programul mai greu de citit i ntreinut. Modificarea programelor, n astfel de situaii, devine mai dificil din moment ce orice modificare poate afecta codul din mai multe clase. Cu ajutorul ablonului mediator comunicaia dintre obiecte este ncapsulat n obiectul mediator. Obiectele nu mai comunic direct ntre ele, ci comunic n schimb prin intermediul mediatorului. Acest lucru reduce dependena ntre obiecte, micornd cuplarea. n contextul acestei diagrame termenul de coleg este utilizat pentru a desemna un obiect ce dorete s comunice cu alte obiecte din acelai grup, un grup avnd un singur moderator.

Fig. 8.23 ablonul mediator Mediator - definete interfaa de comunicare ntre obiecte ConcreteMediator - implementeaz interfaa Mediator i coordoneaz comunicarea ntre objecte. tie care sunt toate obiectele ce doresc s comunice i scopurile acestor comunicri. ConcreteColleague comunic cu alte obiecte colegi cu ajutorul mediatorului. ablonul mediator se poate combina cu ablonul singleton, dac o clas concret mediator are sens s fie instaniat o singur data. ntr-un astfel de caz, dac aplicaia abstractizeaz mai multe grupuri de colegi, pentru fiecare grup se poate crea cte o clas concret mediator care s fie instaniat o singur dat. ablonul mediator nu trebuie confundat cu ablonul proxy. Diferena principal este faptul c mediatorii i colegii nu sunt creai pe baza aceleiai interfee (sau clase abstracte). Un proxy este imaginea unui alt obiect, prin urmare structura unui proxy depinde destul de mult de structura obiectului destinaie. Nu degeaba ablonul proxy este inclus n grupul abloanelor structurale. Structura unui mediator nu este imaginea n oglind a unui obiect coleg, ceea ce i d posibilitatea s transmit mesajele spre mai multe tipuri de clase concrete de colegi, altfel spus s medieze mesajele ntre colegi cu structuri diferite. Exist asemnri ntre ablonul mediator i alte abloane la lista de avantaje: un coleg (binevoitor) poate s transmit anonime (avantaj ntlnit i la proxy);
27

un coleg (rspndac) poate s transmit acelai mesaj mai multor obiecte (avantaj ntlnit i la ablonul compozit); un mediator (securist) poate s foloseasc liste de control al accesului (avantaj ntlnit i la proxy); un mediator (mai lene) poate atepta mai multe mesaje de la colegi pentru a lansa o anumit operaiune (avantaj specific ablonului mediator). Exemplu de folosire a ablonului moderator: organizarea unor vizite (de exemplu la Moscova) poate fi realizat prin intermediul unui moderator (de exemplu ambasadorul rus la Bucureti). Utiliznd terminologia acestui ablon, colegi sunt persoanele ce urmeaz s se ntlneasc. Din pcate, ablonul mediator nu reflect i relaii de subordonare ntre colegi. Un alt exemplu (total rupt de cel anterior) este cel al unei reele de spionaj n care colegi sunt spionii i persoanele decidente din structurile de informaii. Mediatorii n acest exemplu sunt persoanele de legtur, care fac ca de cele mai multe ori colegii s nu se cunoasc ntre ei.

8.3.2 Observator
ablonul observator este un ablon de proiectare n care un obiect gestioneaz o list cu proprii dependeni, pe care i anun automat de eventualele modificri de stare, de obicei prin apelarea anumitor metode. De multe ori acest ablon este folosit pentru implementarea sistemelor distribuite.

Fig. 8.24 ablonul observator Clasa Subject este o clas abstract (sau o interfa) ce asigur ataarea i scoaterea observatorilor. Clasa conine pe lng o list privat cu observatori i urmtoarele metode:
28

attach( ) adaug un nou observator n list; detach( ) elimin un observator din list; notifyObserver ( ) anunt fiecare observator asupra unei schimbri de stare prin apelarea metodelor update( ) ale acestora. Clasa ConcreteSubject este elementul de interes al observatorilor. Ea trimite o notificare tuturor observatorilor prin apelarea metodei notifyObserver( ) din clasa ei printe. Clasa ConcreteSubject conine pe lng interfaa Subject metoda GetState ce returneaz starea subiectului de observat. Clasa Observer definete o interfa pentru anunarea tuturor observatorilor asupra modificrilor survenite n subiect. Interfaa const ntr-o metod ce va fi suprascris de fiecare observator concret. Clasa ConcreteObserver gestioneaz o referin ctre clasa ConcreteSubject i conine operaia update( ). Cnd acest operaie este apelat de ctre subiect, ConcreteObserver apeleaz operaia GetState a subiectului pentru a-i actualiza informaia privind starea subiectului. Operaia update( ) poate primi eventual parametri cu informaii generale ale evenimentului aprut, informaii utile observatorului.
public class Observer { public void update () { } } public abstract class Subject { private ArrayList<Observer> mObserver = new ArrayList<Observer>(); public void attach (Observer o) { mObserver.add(o); } public void detach (Observer o) { mObserver.remove(o); } public void notifyObserver () { for (Observer o : mObserver){ o.update(); } } } public class ConcreteSubject extends Subject { private String state; public String getState () { return state; } public void setState (String val) { this.state = val; System.out.println("Subiectul " + this.toString() + isi anunte toti observatorii de schimbarea starii!"); this.notifyObserver(); } }

" incepe sa

29

public class ConcreteObserver extends Observer { private ConcreteSubject mConcreteSubject = new ConcreteSubject(); public void update () { System.out.println("Observatorul " + this.toString() + " a fost anuntat de schimbarea starii Subiectului " + mConcreteSubject.toString() + "!"); System.out.println("Observatorul " + this.toString() + " citeste noua stare " + mConcreteSubject.getState() + "!"); } public ConcreteSubject getmConcreateSubject () { return mConcreteSubject; } public void setmConcreteSubject (ConcreteSubject s) { mConcreteSubject = s; } }

Codul care utilizeaz ablonul observator:


ConcreteSubject subj = new ConcreteSubject(); ConcreteObserver obs1 = new ConcreteObserver(); ConcreteObserver obs2 = new ConcreteObserver(); ConcreteObserver obs3 = new ConcreteObserver(); subj.attach(obs1); obs1.setmConcreteSubject(subj); subj.attach(obs2); obs2.setmConcreteSubject(subj); subj.attach(obs3); obs3.setmConcreteSubject(subj); subj.setState("DE TEST");

ablonul observator este utilizat atunci cnd modificarea strii unui obiect afecteaz alte obiecte i nu se tie la momentul scrierii codului exact ce obiecte vor trebui anunate. Exemplu de folosire a ablonului observer: implementrarea modurilor de lucru, cnd ntr-o fereastr de dialog utilizarea unui obiect poate presupune disponibilizarea sau indisponibilizarea altor obiecte. n terminologia acestui ablon toate obiectele de pe un formular sunt observatori, iar subiectul concret de observat este chiar formularul. Fiecare obiect n parte nu trebuie s modifice direct celelalte obiecte de pe formular pentru c ar trebui s cunoasc mulimea acestora. Aceeai funcionalitate a modurilor de lucru ar putea fi implementat i cu ajutorul ablonului mediator.

8.3.3 Lan de responsabiliti


ablonul lanului de responsabiliti (chain of responsibility) este un ablon comportamental care permite evitarea cuplrii directe a expeditorului unei cereri cu un anumit destinatar, folosindu-se n acest sens clase intermediare.

30

Fig. 8.25 ablonul lan de responsabiliti Conform acestui ablon un client cere unui obiect ConcreteHandler s fie realizat o aciune, dar acesta poate s transmit sarcina unui alt obiect ConcreteHandler n funcie de un anumit algoritm. Avantajele unui astfel de ablon: - expeditorul poate s nu cunoasc exact care este destinatarul final al cererii sale, pe el interesndu-l doar ca respectiva sarcin s fie ndeplinit (asemnare cu abloanele proxy i mediator); - clasele intermediare pot alege destinatarii, gestionnd eventual i gradul de solicitare al acestora i gradul de solicitare a sistemelor de calcul pe care ruleaz acetia (asemnare cu ablonul proxy, pentru c i un proxy poate s aleag RealSubject n funcie de gradul de solicitare); - o cerere poate fi procesat de mai muli destinatari, n acelai timp, secvenial sau respectnd chiar anumite fluxuri de cereri (asemnare cu ablonul mediator); - clasele intermediare pot realiza log-uri ale cererilor (asemnare cu abloanele proxy, mediator, observator etc.); - lipsa oricrui potenial destinatar poate fi aflat de ctre expeditor printr-un mesaj primit de la clasele intermediare (asemnare cu abloanele proxy i mediator). Din cele de mai sus reies o serie de asemnri ntre ablonul mediator i lanul de responsabiliti, mai exact rolul Mediator seamn cu ConcreateHandler i rolul Coleg seamn cu rolul Client. Deosebirile dintre ablonul mediator i lanul de responsabiliti constau n: - un mediator este de obicei singur pentru un grup de colegi, dar obiectele de tip ConcreateHandler au sens s fie mai multe (ca s ias lanul); - mediatorul nu este un obiect care s i execute efectiv aciunea cerut, dar n lanul de responsabiliti, un obiect de tip ConcreateHandler va realiza aciunea cerut; - n ablonul mediator este vorba de mai muli colegi, dar la un lan de responsabiliti exist un singur obiect cu rolul de client. Deosebirea principal dintre ablonul proxy i lanul de responsabiliti este faptul c un ConcreateHandler din lanul de responsabiliti este n acelai timp un proxy (poate da mai departe sarcina), dar i un RealSubject (poate executa sarcina). Un exemplu de lan de responsabiliti este modul de autorizare a unor tranzacii de ctre anumii angajai n funcie de mrimea acestor tranzacii. Aprobarea unui credit poate fi fcut la nivelul unui ofier de credit, manager al departamentului de credite, ef de filial sau sucursal i n rare cazuri un credit are nevoie i de aprobarea managerilor din central. Clasa Functie are rolul de ConcreteHandler, n ea existnd:
31

- un atribut cu obiectul ce reprezint nivelul ierarhic superior (un obiect creat tot pe baza clasei Functie); - un atribut ce ne indic limita creditului ce poate fi aprobat fr a fi trimis i la nivelul ierarhic superior.

Fig. 8.26 Exemplu de utilizare a ablonului lan de responsabiliti Metoda proceseazDosarCredit poate fi implementat astfel:
public void proceseazaDosarCredit( Credit c ) { if ( c.suma <= limitaCredit ) { //proceseaz efectiv dosarul n sensul aprobrii sau respingerii lui } else if ( superior != null ) superior.proceseazaDosarCredit(c); }

Exemplul de mai sus poate fi extins prin crearea a cte o clas specializat din clasa Functie pentru fiecare funcie (ofier de credit, manager al departamentului de credite, ef de filial sau sucursal, manager din central) i suprascrierea metodei proceseazDosarCredit n aa fel nct algoritmul de decizie privind cui i cade n sarcin dosarul respectiv s difere la fiecare nivel. Exist variante ale acestui ablon n care obiectele de tip ConcreateHandler: - retransmit cererea mai multor obiecte, formndu-se arbori de responsabiliti; - retransmit recursiv cererea; - rezolv o parte a problemei i transmit mai departe doar partea neprocesat din comand. ablonul seamn cu aruncarea mei moarte n ograda vecinului, n funcie de starea de putrefacie a bietului animal. Cu ct starea de putrefacie este mai mare cu att pisica va ajunge la un vecin mai ndeprtat (n sperana c toi vecinii vor pstra aceeai direcie i fiecare vecin are propria limit de suportare a mirosului). Biata pisic se oprete la primul vecin care i suport mirosul (dac nu rmne n perpetuum mobile).

32

8.3.4 Memento (Amintire)


ablonul amintire (memento) este un ablon comportamental destinat salvrii diferitelor stri curente ale unor obiecte i revenirea la aceste stri. n acest ablon se folosete o clas de amintire (Memento) ce conine aceleai proprieti de stare ca i clasa obiectelor de salvat (Originator). Obiectele de amintire se pot gestiona eventual ntr-o colecie (Caretaker). Obiectul de salvat trebuie s conin cte o metod pentru fiecare din aceste dou aciuni: salvare (saveToMemento) i revenire la stare anterioar (restoreFromMemento).

Fig. 8.27 ablonul memento


public class Memento { private String stare1; private int stare2; /*plus metodele get si set specifice acestor atribute*/ } public class Caretaker { private ArrayList<Memento> mMemento = new ArrayList<Memento>(); public void addMemento (Memento m) { mMemento.add(m); } public Memento getMemento (int index) { return mMemento.get(index); } /*plus metodele get si set specifice acestor atribute*/ } public class Originator { private Caretaker c = new Caretaker(); private String stare1; private int stare2; public void saveToMemento () { Memento m = new Memento();

33

m.setStare1(stare1); m.setStare2(stare2); c.addMemento(m); } public void restoreFromMemento (int index) { Memento m = c.getMemento(index); this.stare1 = m.getStare1(); this.stare2 = m.getStare2(); } /*plus metodele get si set specifice acestor atribute*/ }

Clientul care ar folosi un astfel de ablon ar ncepe prin a modifica strile obiectului Originator i ar utiliza din cnd n cnd metoda saveToMemento pentru a salva diferitele stri ale acestuia. Revenirea la o stare anterioar se face tiind un numr de ordine al acesteia n cadrul coleciei de stri (numrtoarea ncepe de la 0, cel puin n exemplul urmtor).
Originator orig = new Originator(); orig.setStare1("ALFA"); orig.setStare2(6); orig.saveToMemento(); orig.setStare1("BETA"); orig.setStare2(7); orig.saveToMemento(); orig.setStare1("GAMA"); orig.setStare2(8); orig.saveToMemento(); orig.restoreFromMemento(1);/*aici se revine la starile BETA & 7*/ System.out.println(orig.getStare1()); System.out.println(Integer.toString(orig.getStare2()));

8.3.5 Strategie
ablonul strategie ne ajut s alegem un anumit algoritm de utilizat n funcie de un context, n momentul rulrii. ablonul conine un grup de algoritmi, fiecare din acetia fiind ncapsulat ntr-un obiect (the tip ConcreteStrategy). Clienii ce folosesc algoritmii (instane ale clasei cu rolul Context) nu depind de acetia, variind n mod independent.

34

Fig. 8.28 ablonul strategie Obiectele de tip context conin cte un obiect strategy, dar alegerea unei strategii concrete se realizeaz n funcie de context. Conform ablonului strategy comportamentul unei clase nu ar trebui s fie motenit, ci specific contextului n care ruleaz i ncapsulat utiliznd interfee. De exemplu, o aplicaie de salarizare poate lua n calcul diferitele tipuri de salarizare: n regie sau n acord. n practic, pentru fiecare dintre aceste tipuri de salarizare exist diverse variante, putndu-ne atepta ca la un moment dat s se doreasc adugarea unui nou algoritm la lista iniial. Conform ablonului strategie realizm urmtoarele clase:

Fig. 8.29 Exemplu de ablon strategie Dac inem mori s nu utilizm ablonul strategie la realizarea unei aplicaii care s implementeze diferitele tipuri de salarizare ntr-o posibil metod CalculSalarBrut, atunci: 1) n metoda CalculSalarBrut am scrie o structur alternativ, n ramurile creia am include algoritmii specifici fiecrui tip de salarizare (metoda capt volum i mprirea sarcinilor la mai muli programatori devine ciudat cnd este vorba de o singur metod); sau 2) am crea o ierarhie de angajai n funcie de tipul de salarizare (clasa angajat poate face parte din ierarhii fcute dup alte criterii i folosirea unei ierarhii cu mai multe criterii de specializare ridic probleme de redundan a codului). Cele dou soluii alternative nu separ clientul (i eventual ierarhia din care face parte clientul) de comportamentul dorit. Un alt exemplu, pentru iubitorii de jocuri electronice (mai ales de shootere): dac avem o ierarhie de lupttori cu diverse caracteristici i o metod atac, ce face efectiv metoda atac nu ine de ierarhia de lupttori, ci de arma deinut la momentul respectiv. n acest exemplu, lupttorii au rolul Context, iar diferitele arme au rolul de ConcreteStrategy.

35

8.3.6 ablonul iterator


ablonul iterator este folosit pentru a accesa elementele unui agregat (a unei colecii) n mod secvenial, fr a ne folosi de caracteristicile acestor elemente. n orice moment unul din elementele coleciei este considerat ca fiind elementul curent.

Fig. 8.30 ablonul iterator Operaii ale elementelor coleciei de parcurs ar putea fi: - currentItem (ghici ce face fiecare operaie); - first; - last; - next; - previous; - hasNext; - hasPrevious; - isFirst; - isLast. ablonul iterator are un grad mai mare de importan n mediile de dezvoltare n care nu sunt implementate complet tipuri de date compuse (vectori, liste, stive). l ntlnii implementat n RecordSet-urile ADO, DAO sau RDO specifice mediilor de dezvoltare Microsoft.

36

8.3.7 ablonul interpreter


ablonul interpreter descrie cum se pot interpreta expresiile ntr-un anumit limbaj. El i gsete utilitatea n aplicaiile economice n care se dorete salvarea unor formule de calcul ntr-un format accesibil utilizatorilor finali i folosirea ulterioar de ctre aplicaie a acestor formule. Conform ablonului interpreter att operanzii, ct i operatorii dintr-o expresie ar trebui s aib aceeai interfa.

Fig. 8.31 ablonul interpreter O expresie terminal este o expresie care nu poate fi mprit n expresii mai mici, ca n cazul unei expresii nonterminale. O expresie nonterminal se comport ca un evaluator de expresii. Acest evaluator trebuie s mpart expresia de interpretat n mai multe pri cu un parser. Tot evaluatorul trebuie s parcurg fiecare parte a expresiei: - cnd ntlnete un operand (o variabil pe care are voie utilizatorul s o foloseasc ntr-o anumit formul) l introduce ntr-o stiv; - cnd ntlnete un operator extrage din stiv valorile operanzilor afectai i introduce n loc rezultatul aplicrii operatorului asupra operanzilor. Dac se pleac de la o expresie corect la sfritul parcurgerii acesteia n stiva utilizat va rmne o singur valoare, ea fiind chiar rezultatul interpretrii. Exemple de aplicaii n care ar putea fi utilizat ablonul interpreter: - aplicaii de salarizare; - aplicaii de procesare a datelor la importul sau exportul lor din diferite sisteme; - aplicaii de interpretare a unui dialect SQL sau de traducere dintr-un dialect SQL n altul. Un interpretor poate fi vzut i ca o cutie neagr creia i se d o expresie i care returneaz un rezultat. Cum nu trebuie s reinventm roata putem folosi interpretore deja existente, cum ar fi cele pentru scripturi:
import javax.script.ScriptEngineManager; import javax.script.ScriptEngine; import javax.script.ScriptException; ScriptEngineManager mgr = new ScriptEngineManager(); ScriptEngine jsEngine = mgr.getEngineByName("JavaScript"); try {

37

jsEngine.eval("a = 1; b = 2; c = a + b; print(c);"); } catch (ScriptException ex) { ex.printStackTrace(); }

Rularea codului de mai sus ar duce la evaluarea expresiei trimis metodei eval i anume la calculul i afiarea variabilei c.

8.3.8 ablonul command


Conform ablonului command un obiect poate ncapsula toate informaiile necesare pentru apelarea unei metode a altui obiect, cum ar fi: numele metodei de apelat, obiectul ce deine metoda i valorile de transmis parametrilor.

Fig. 8.32 ablonul command Clientul instaniaz obiectul de tip comand i l pregtete pentru a fi apelat la un moment ulterior (transmindu-l invoker-ului). Obiectul invoker conine o list de comenzi i decide cnd va fi apelat obiectul comand. Obiectul receiver este cel care va efectua o aciune ca urmare a lansrii n execuie a comenzii. Beneficiile acestui ablon in de faptul c execuia unei anumite metode poate fi pregtit din timp, n aa fel nct aceasta s fie lansat fr s i se tie numele, obiectul de care aparine i momentul exact al execuiei. ablonul command poate fi utilizat pentru a realiza aplicaii cu: - funcionaliti de tip undo; - comportament tranzacional; - progress bar sincronizat cu execuia unui grup de comenzi; - funcionaliti de tip wizard; - nregistrri de macro-uri; De exemplu, dac un ppuar (client) dorete s pun o ppu (receiver) s se bucure (concretecommand) folosete un ef de campanie (invoker), iar acesta i transmite ppuii s opie (metoda action din ablon).

38

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