8 Şabloane de proiectare (Design patterns

)
În domeniul proiectării software există soluţii 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 soluţie pentru o anumită problemă, soluţie care, în timp, s-a dovedit folositoare în situaţii asemănătoare. Şabloanele de proiectare orientate obiect conţin clase, relaţiile şi interacţiunile dintre ele. Clasele conţinute nu sunt într-o formă finală, structurile acestora putându-se extinde cu elementele specifice fiecărui proiect. Algoritmii nu sunt consideraţi ca fiind şabloane de proiectare deoarece ei rezolvă probleme de implementare. Folosirea şabloanelor de proiectare poate duce la creşterea atât a vitezei de dezvoltare a software-ului, cât şi a calităţii acestuia, prin utilizarea unor soluţii testate, care şiau dovedit eficacitatea. Proiectarea software-ului presupune luarea unor decizii a căror corectitudine se dovedeşte mai târziu, la partea de implementare. Reutilizarea unor şabloane de proiectare ajută la prevenirea unor probleme majore şi îmbunătăţeşte claritatea codului pentru programatorii şi arhitecţii 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 transformării celor mai utilizate şabloane de proiectare în componente se vorbeşte 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 uşurarea muncii de proiectare a aplicaţiilor software. De exemplu, mai există în domeniul software aşa numitele şabloane arhitecturale (architectural patterns), ce descriu, aşa cum le sugerează şi denumirea, soluţiile unor probleme de arhitectură software. Şabloanele de proiectare pot fi grupate în mai multe categorii:  şabloane creaţionale (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 responsabilităţi (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 creăm o diagramă de clase şi dăm în spaţiul 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 fără să îl vizualizăm într-o clasă de diagrame putem da click dreapta pe nodul Model şi vom găsi aceeaşi opţiune „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 opţiunea „Generate Code” (click dreapta pe clasa UML).

8.1 Şabloane creaţionale
Şabloanele creaţionale 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 fără a fi necesare schimbări asupra codului ce foloseşte clasele de bază.

8.1.1 Şablonul Singleton
Singleton este un şablon folosit pentru a restricţiona instanţierea unei clase la un singur obiect. Acest concept este uneori generalizat pentru a restricţiona instanţierea la un anumit număr de obiecte. Şablonul singleton se implementează prin crearea unei singure clase ce conţine 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ă apartenenţa 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 instanţieri ale clasei nu se mai alocă memorie pentru un atribut static, dar toate obiectele din acea clasă pot accesa aceeaşi variabilă statică, aflată în aceeaşi zonă de memorie. Pe lângă cele specificate mai sus, o clasă singleton mai poate conţine atribute şi operaţii specifice domeniului în care este utilizat. Şablonul singleton prevede şi existenţa 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 instanţiată de mai multe ori şi nu ar mai ieşi un singleton. Neexistând constructorul, instanţa unică se obţine 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 instanţiat (atributul static de acelaşi tip cu clasa în care este inclus).

2

mai degrabă grăbită şi risipitoare). marie = sabloane_creationale.out.Singleton marie. public static Singleton instance () { if(uniqueInstance == null) { uniqueInstance = new Singleton(). String s = new Integer(aceeasiMarie. } return uniqueInstance.Singleton. System. Exemple de utilizare a şablonului singleton: .getSingletonData()). 3 .toString(). La lansarea codului de mai sus descoperim că.. 8..clasa user într-o aplicaţie în care se doreşte gestiunea unitară a drepturilor unui utilizator logat. dacă o astfel de instanţă nu există deja (această modalitate de instanţiere este denumită instanţiere leneşă). System.instance().Fig.instance().setSingletonData(3). String s = new Integer(marie. caz în care metoda instance( ) trebuie doar să returneze o referinţă la acest obiect: public static Singleton instance() { return uniqueInstance.println("Atributul singletonData primeste valoarea " + s)..1 Reprezentarea unei clase singleton Instanţa unică poate fi creată: 1) implicit la definirea acestui element (o instanţiere nu tocmai leneşă. marie.Singleton. private sabloane_creationale.println("Atributul singletonData avea deja valoarea " + s). acelaşi obiect uniqueInstance).out. } 2) explicit în metoda statică instance( ).toString(). private sabloane_creationale..Singleton aceeasiMarie. aceeasiMarie = sabloane_creationale. } Putem testa clasa Singleton la crearea a două obiecte: „marie” şi „aceeasiMarie”.getSingletonData()). aceeaşi valoare a atributului singletonData) şi asta pentru că este aceeaşi „marie” (. indiferent de ceea ce se spune „aceeasiMarie” are aceeaşi pălarie (pardon .

într-un joc de şah clasa jucător ar trebui să fie instanţiată numai de două ori.două atribute statice de tipul clasei (uniqueWhite şi uniqueBlack). deoarece culoarea este stabilită doar la instanţierea jucătorului şi nemodificată pe parcursul jocului.3 Diagrama de clase necesară creării propriului singleton 4 . De exemplu.două metode statice care să returneze cele două instanţe unice (getUniqueWhite şi getUniqueBlack). NetBeans ne dă posibiliatea să creăm propriile şabloane de proiectare pe lângă cele prestabilite folosind opţiunea Window\Other\UML Design Center. color = "White".un constructor privat. ci la un număr finit de instanţe (de preferat nu număr mic). . - Fig. În acest proiect putem specifica propriul singleton creând următoarea diagramă de clase: Fig. Soluţia în acest caz presupune: . } return uniqueWhite. Aici putem crea un nou proiect cu şabloane. adică să le dea o nuanţă de alb sau de negru: public Player getUniqueWhite() { if (uniqueWhite == null) { uniqueWhite = new Player(). } Observaţie: în exemplul de mai sus nici nu este nevoie de o operaţie setColor. Pot exista şi versiuni ale şablonului singleton. 8. 8. .clasa destinată conexiunii cu baza de date atunci când se doreşte ca aplicaţia să folosească la un moment dat o singură bază de date. denumit eventual MyPatterns. cele în care se limitează instanţierea unei clase nu doar la o instanţă.2 Clasa singleton Player într-un joc de şah Metodele statice din acest exemplu ar trebui să se asigure mai întâi că există instanţele statice corespunzătoare şi apoi să le iniţializeze.

spre bucuria ei). Fig. e puţin cam târziu să mai introducem în ecuaţie şi pasărea cu metoda ei factory de făcut ouă. în aşa fel încât să folosească o nouă clasă concretă factory. sunt create obiect concrete. Acest şablon poate fi implementat cu dificultate atunci când este folosit pentru clase ce au deja clienţi. dar codul client le accesează doar prin interfaţa lor abstractă. Clasele factory conţin câte o metodă factory pentru fiecare tip de obiect ce trebuie creat. struţ). Şablonul este folosit în ierarhiile de clase paralele. 5 . putem dezvolta o ierarhie de păsări (găină. 8. Conform acestui şablon. nedepinzând de tipurile concrete. raţă. Adăugarea de noi tipuri concrete sistemului se face prin modificarea codului client. Şablonul metodă factory presupune crearea unei clase de bază (Creator) ce conţine o metodă destinată creării obiectelor de un anumit tip (factoryMethod).8. Codul client lucrează doar cu tipul abstract de factory.1. ce produc anumite tipuri de ouă.4 Şablonul metodă factory Subclase ale clasei factory pot suprascrie metoda factory pentru a se specifica anumite subtipuri ale obiectelor obţinute. Conform acestui şablon se creează o clasă abstractă factory ce va sta la baza mai multor clase concrete factory. Adică dacă începem prin aplicaţie să folosim constructorul implicit de ouă.3 Clasă abstractă factory Şablonul abstract factory asigură o modalitate de grupare a mai multor metode factory ce au elemente comune.2 Metodă factory Termenul factory (fabrică) este utilizat în acest context pentru a arăta locul destinat construirii de obiecte. De exemplu. Fiecărui element din ierarhia de păsări îi corespunde un anumit tip de ou (nu punem săraca găină să producă un ou de struţ.1. 8. când obiectele dintr-o ierarhie creează obiecte corespunzătoare din cealaltă ierarhie.

1. Pentru implementarea acestui şablon se declară o clasă de bază abstractă ce specifică o operaţie clonePrototype. altfel spus a reţetelor de fabricaţie.a evita folosirea subclaselor concrete factory în aplicaţiile client. Fig. Obiectele de obţinut nu fac parte dintr-o anumită ierarhie de clase.5 Şablonul prototip 8.Fig. cu metode constructor.5 Builder Şablonul builder ajută la abstractizarea paşilor construirii unor obiecte.4 Prototip Şablonul constă în folosirea unei instanţe drept prototip pentru crearea (clonarea) de noi obiecte.4 Şablonul clasă abstractă factory 8. Şablonul protoype este folosit pentru: .1. 8. Orice clasă ce are nevoie de un constructor polimorfic va deriva din clasa de bază abstractă şi implementează operaţia clonePrototype. 8.a evita crearea de obiecte în mod clasic. . dar există constrângerea ca valorile atributelor acestora să nu aibă sens decât într-o anumită 6 .

Cu un astfel de şablon clasa client poate modifica furnizorii de funcţionalităţi fără să îşi modifice propria structură. dar nu şi interfaţa dorită.1 Adaptor Adaptorul (cunoscut şi sub numele de wrapper) este o clasă ce permite traducerea unor interfeţe în alte interfeţe. Cum toate produsele (obiectele) obţinute sunt instanţe ale aceeleiaşi clase înseamnă că toate au aceleaşi părţi şi prin urmare toate se pot obţine prin respectarea aceleiaşi secvenţe de construire. În acest fel. Adaptorul permite unor clase cu interfeţe incompatibile să interacţioneze. Fiecare combinaţie de valori ale atributelor se obţine cu un anumit builder (cu o anumită reţetă de fabricaţie). doar utilizând alţi adaptori. Motivul folosirii unei clase abstracte poate fi în acest caz agregarea în Builder a unui obiect produs protejat (protected). din acest motiv clasa adaptor este utilizată în mod direct de către clasa client. Cel mai reuşit exemplu de utilizare a şablonului builder este cel de pe wikipedia unde clasei cu rolul product este clasa pizza. Acest şablon este folositor atunci când o clasă deja implementată (clasa de adaptat sau clasa furnizor) asigură funcţionalităţile dorite. Fig. clasele cu rolurile concretebuilder sunt diferitele reţete de pizza. În acelaşi timp adaptorul ştie să utilizeze funcţionalităţile clasei de adaptat. clasa client este independentă de structura interfeţei de adaptat. 8.2. Metoda construct din clasa director include o secvenţă de apelări a metodelor de construire a părţilor (atributelor) produselor.6 Şablonul builder Clasa director este cea care construieşte efectiv produsul cu ajutorul unui builder (reţete de fabricaţie) pe care îl conţine. Aceşti builder-i sunt organizaţi într-o ierarhie de clase. Pot exista variante ale acestui şablon în care Builder este o clasă abstractă şi nu o interfaţă. 7 . 8.combinaţie. Adaptorul ştie să răspundă cel puţin la interfaţa dorită de client. iar clasa cu rolul director este clasa.2 Şabloane structurale 8.

specificRequest(). Fig.8 Şablonul class adapter cu implementare multiplă de interfeţe 8 . adaptoare care implementează ambele interfeţe şi care în metodele ce implementează operaţiile interfeţei dorite se face trimitere la operaţiile interfeţei de adaptat = class adapter. În acest caz se poate vorbi de o adaptare bidirecţională a claselor. în funcţie de modul în care adaptorul reuşeşte să utilizeze funcţionalităţile clasei de adaptat: 1. 8. } 2. 8. adaptoare ce implementează interfaţa dorită de client şi care conţin în plus o instanţă a clasei de adaptat = object adapter.7 Şablonul object adapter În metoda request a adaptorului se scrie în acest caz: public void request () { furnizor. Fig.Există două tipuri de adaptoare.

ulterior dorindu-se utilizarea şi a altor servere. mai exact folosind metoda sendMessage a acestuia. Figura 8.9 face referire la clasele specifice unei astfel de aplicaţii iniţiale în care clientul.8 face referire la implementările a două interfeţe şi nu la extinderea a două clase). Metoda sendText a adaptorului suprascrie metoda sendText a serverului iniţial făcând delegând activitatea de realizat membrului obiect de tipul celuilalt server. 8.10 Aplicaţie de messenger cu un object adapter 9 . Şablonul class adapter presupune folosirea moştenirii multiple. Iniţial un client de messenger poate fi dezvoltat pentru un singur server. 8.nu toate mediile de programare suportă complet moştenirea multiplă (de aceea figura 8.pot apare conflicte între operaţiile celor două interfeţe când aceste operaţii au aceeaşi semnătură dar o semantică diferită Un exemplu de utilizare a şablonului object adaptor este cel în care aplicaţiile client de messenger pot utiliza diferite servere de messenger. utilizează metoda sendText dintr-un anumit server. de unde îi vin şi anumite dezavantaje: .8 poate fi folosit atât pentru o aplicaţie ce depinde de ClassA.Adaptorul descris în figura 8. cât şi invers. . dar care dispune de ClassB. în metoda sendText. Fig. clasa ServerMessenger se poate specializa într-un adaptor ce conţine ca şi membru un obiect de tipul unui alt server. Fig.9 Diagrama claselor într-o aplicaţie de messenger Pentru utilizarea unui alt server de messenger.

situaţie în care operaţia se lansează pentru toate elementele agregate. Şablonul compozit ne ajută în acest caz ca o operaţie specifică unui ziarist (cea de a ataca) să fie lansată (de un mogul) pentru un întreg trust. Una din situaţiile în care şablonul compozit se face util este cea în care se gestionează structuri ierarhice. reviste etc. . citire etc.2 Compozit Şablonul compozit permite unui grup de obiecte să fie tratat ca un singur obiect. 8. Soluţia propusă de şablon este de a obţine elementul compozit (nodul în cazul structurilor ierarhice) din specializarea clasei destinată componentelor (frunzelor).). cu un efort minim. fără a apela fiecare ziarist în parte.11 Şablonul compozit Şablonul nu este util doar în cazul structurilor ierarhice. redacţii care aparţin de anumite publicaţii (ziare. iar în cazul operaţiilor specifice domeniului afacerii îşi delegă sarcinile operaţiilor corespunzătoare ale obiectelor copil. Diferenţa structurală dintre noduri şi frunze face ca lucrul cu structuri ierarhice să fie complex. În exemplul următor este vorba de ziarişti care fac parte din redacţii. 8.). ci apelând doar operaţia ataca a obiectului trust. ci în toate relaţiile de compunere în care operaţiile unui grup de obiecte include operaţiile unui singur obiect. Cu ajutorul acestui şablon o operaţie specifică elementelor componente poate fi lansată şi pentru un agregat.Alte exemple de utilizare a adaptoarelor: . Clasa destinată componentelor conţine pe lângă implementarea operaţiilor specifice domeniului afacerii şi declararea interfeţei pentru accesarea şi gestiunea componentelor copil (adăugare.comenzile de aprovizionare ce pot fi transmise direct furnizorilor într-un mediu B2B. .2. Fig. Clasa compozită implementează metodele de manipulare a componentelor copil. ştergere. 10 . publicaţii ce aparţin unor trusturi de presă.wrapper-ele din bazele de date federative (DB2) care fac legătură între baze de date eterogene.coletele de transmis prin intermediul oficiilor poştale diferite.

add(popescu).println("Hau hau!"). } } public class Grup implements Componenta { private ArrayList<Componenta> mComponenta = new ArrayList<Componenta>(). sabloane_structurale. sabloane_structurale.add(ionescu).Grup().ataca().out.11 Şablonul compozit public interface Componenta { public void ataca (). redactie.Grup().Ziarist(). 11 .Fig.Ziarist altescu = new sabloane_structurale.Ziarist(). 8.Ziarist().Grup(). sabloane_structurale.Grup ziar = new sabloane_structurale.Grup trust = new sabloane_structurale.remove(c). redactie. sabloane_structurale. } public void remove (Componenta c) { mComponenta.Ziarist ionescu = new sabloane_structurale.Grup redactie = new sabloane_structurale. } } Dacă declaraţiile de mai sus ar face parte din pachetul sabloane_structurale.add(c). intrând în pielea unui mogul am putea utiliza codul următor: sabloane_structurale. } } public void add (Componenta c) { mComponenta. } public class Ziarist implements Componenta { public void ataca () { System.Ziarist popescu = new sabloane_structurale. sabloane_structurale. public void ataca () { for (Componenta componenta : mComponenta) { componenta.

8.2.redactie.ataca(). în speranţa că interfaţa faţadei va rezolva aceste probleme.12 Şablonul facade 12 . Cu ajutorul acestui şablon o bibliotecă software devine mai uşor de înţeles şi de utilizat.add(redactie). trust. trust. 8.3 Facade (faţadă) O faţadă este un obiect ce asigură o interfaţă simplificată spre un grup de clase. O faţadă este recomandată şi atunci când trebuie să folosim o colecţie de clase ce folosesc interfeţe prost proiectate sau greu de înţeles.add(ziar). Fig. reducândui dependenţa de restul codului (scade cuplarea). ziar.add(altescu).

încarcă obiecte persistente la prima utilizare. 8. o dată creată. server etc. 3) Protective proxy = clasă de control al accesului la obiecte mai sensibile din punct de vedere al securităţii. CarteaMare. Fig. RegistruDeCasa. cum ar fi: a. 2) Remote proxy = asigură o reprezentare locală pentru un obiect dintr-un spaţiu diferit de memorie. b. obiectul real este creat la prima cerere de acces la acesta.) care funcţionează ca o interfaţă pentru altceva. Stocuri. În acest caz metoda contabilizeaza din faţada ContabilitateSiGestiune include toată secvenţa de apelări a claselor: RegistruJurnal. Obiectul proxy verifică dacă expeditorul are dreptul să transmită mesaje destinatarului. ci realizează în plus o serie de acţiuni. ci doar că o tranzacţie.În exemplul din figura 8. trebuie transmisă faţadei ContabilitateSiGestiune pentru înregistrarea acesteia în contabilitate şi afectarea gestiunilor corespondente. 4) Smart proxy = clasă care nu doar transmite mai departe o operaţie de realizat. RegistruDeBanca. 8.12 cel care crează obiectele de tip tranzacţie (dintr-o interfaţă utilizator sau dintr-o procedură de import) nu trebuie să cunoască detaliile claselor de contabilitate şi gestiune. verifică dacă obiectul adevărat este blocat pentru alte accese (asigură prelucrări tranzacţionale şi diferite niveluri de izolare) 13 . Un proxy nu face decât să delege acţiunile mai departe unei alte clase.2. în RPC şi CORBA o astfel de funcţionalitatea o asigură un „stub”.4 Proxy La modul general un proxy este o resursă (clasă.13 Şablonul proxy Există patru situaţii în care se recomandă să folosim un astfel de şablon: 1) Virtual proxy = o clasă de acces către obiectele unei alte clase ce presupunhe utilizarea multor resurse. c. numără referirile la un anumit obiect.

devine mai dificilă din moment ce orice modificare poate afecta codul din mai multe clase. Ştie care sunt toate obiectele ce doresc să comunice şi scopurile acestor comunicări. Şablonul mediator nu trebuie confundat cu şablonul proxy. prin urmare structura unui proxy depinde destul de mult de structura obiectului destinaţie. problema comunicării între obiecte devine mai complexă.8. 8.3. ConcreteColleague – comunică cu alte obiecte “colegi” cu ajutorul mediatorului. dacă aplicaţia abstractizează mai multe grupuri de colegi. ci comunică în schimb prin intermediul mediatorului. un grup având un singur moderator. Modificarea programelor.3 Şabloane comportamentale 8. Şablonul mediator se poate combina cu şablonul singleton. ceea ce îi dă posibilitatea să transmită mesajele spre mai multe tipuri de clase concrete de colegi. micşorând cuplarea. Nu degeaba şablonul proxy este inclus în grupul şabloanelor structurale.14 Şablonul mediator Mediator . în astfel de situaţii.defineşte interfaţa de comunicare între obiecte ConcreteMediator .1 Mediator De obicei o aplicaţie este alcătuită dintr-un număr important de clase. altfel spus să medieze mesajele între colegi cu structuri diferite. 14 . pentru fiecare grup se poate crea câte o clasă concretă mediator care să fie instanţiată o singură dată. Un proxy este „imaginea” unui alt obiect. Există asemănări între şablonul mediator şi alte şabloane la lista de avantaje:  un coleg (binevoitor) poate să transmită „anonime” (avantaj întâlnit şi la proxy). dacă o clasă concretă mediator are sens să fie instanţiată o singură data. Obiectele nu mai comunică direct între ele. Structura unui mediator nu este imaginea în oglindă a unui obiect coleg. În contextul acestei diagrame termenul de coleg este utilizat pentru a desemna un obiect ce doreşte să comunice cu alte obiecte din acelaşi grup. ceea ce face programul mai greu de citit şi întreţinut. Fig. Diferenţa principală este faptul că mediatorii şi colegii nu sunt creaţi pe baza aceleiaşi interfeţe (sau clase abstracte).implementează interfaţa Mediator şi coordonează comunicarea între objecte. Cu cât sunt mai multe clase într-o aplicaţie. Cu ajutorul şablonului mediator comunicaţia dintre obiecte este încapsulată în obiectul mediator. Acest lucru reduce dependenţa între obiecte. Într-un astfel de caz.

de obicei prin apelarea anumitor metode. 8. Mediatorii în acest exemplu sunt persoanele de legătură.2 Observator Şablonul observator este un şablon de proiectare în care un obiect gestionează o listă cu proprii dependenţi. Din păcate. şablonul mediator nu reflectă şi relaţii de subordonare între „colegi”. 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 Bucureşti).un coleg (răspândac) poate să transmită acelaşi mesaj mai multor obiecte (avantaj întâlnit şi la şablonul compozit).15 Şablonul observator Clasa Subject este o clasă abstractă (sau o interfaţă) ce asigură ataşarea şi scoaterea observatorilor. Clasa conţine pe lângă o listă privată cu observatori şi următoarele metode:  attach( ) – adaugă un nou observator în listă. 15 . De multe ori acest şablon este folosit pentru implementarea sistemelor distribuite. Fig. care fac ca de cele mai multe ori colegii să nu se cunoască între ei.3.  un mediator (mai leneş) poate aştepta mai multe mesaje de la colegi pentru a lansa o anumită operaţiune (avantaj specific şablonului mediator).  8. colegi sunt persoanele ce urmează să se întâlnească. pe care îi anunţă automat de eventualele modificări de stare.  un mediator (securist) poate să folosească liste de control al accesului (avantaj întâlnit şi la proxy). Un alt exemplu (total rupt de cel anterior) este cel al unei reţele de spionaj în care colegi sunt spionii şi persoanele decidente din structurile de informaţii. Utilizând terminologia acestui şablon.

Clasa ConcreteObserver gestionează o referinţă către clasa ConcreteSubject şi conţine operaţia update( ). gestionând eventual şi gradul de solicitare al acestora şi gradul de solicitare a sistemelor de calcul pe care rulează aceştia. notifyObserver( ) – anuntă fiecare observator asupra unei schimbări de stare prin apelarea metodelor update( ) ale acestora.3 Lanţ de responsabilităţi Şablonul lanţului de responsabilităţi (chain of responsibility) este un şablon comportamental care permite evitarea cuplării directe a expeditorului unei cereri cu un anumit destinatar.  detach( ) – elimină un observator din listă. . informaţii utile observatorului. Şablonul observator este utilizat atunci când modificarea stării unui obiect afectează alte obiecte şi nu se ştie la momentul scrierii codului exact ce obiecte vor trebui anunţate. Aceeaşi funcţionalitate a modurilor de lucru ar putrea fi implementată şi cu ajutorul şablonului mediator. pe el interesându-l doar ca respectiva sarcină să fie îndeplinită. în acelaşi timp.expeditorul poate să nu cunoască exact care este destinatarul final al cererii sale. . când într-o fereastră de dialog utilizarea unui obiect poate presupune disponibilizarea sau indisponibilizarea altor obiecte. secvenţial sau respectând chiar anumite fluxuri de cereri. Clasa Observer defineşte o interfaţă pentru anunţarea tuturor observatorilor asupra modificărilor survenite în subiect. Avantajele unui astfel de şablon: . Clasa ConcreteSubject este elementul de interes al observatorilor. Ea trimite o notificare tuturor observatorilor prin apelarea metodei notifyObserver( ) din clasa ei părinte. Clasa ConcreteSubject conţine pe lângă interfaţa Subject metoda GetState ce returnează starea subiectului de observat. . În terminologia acestui şablon toate obiectele de pe un formular sunt observatori. Exemplu de folosire a şablonului observer: implementrarea modurilor de lucru. Interfaţa constă într-o metodă ce va fi suprascrisă de fiecare observator concret. Când acestă operaţie este apelată de către subiect. iar subiectul concret de observat este chiar formularul.clasele intermediare pot realiza log-uri ale cererilor. . Fiecare obiect în parte nu trebuie să modifice direct celelalte obiecte de pe formular pentru că ar trebui să cunoască mulţimea acestora. 8. Operaţia update( ) poate primi eventual parametri cu informaţii generale ale evenimentului apărut.lipsa oricărui potential destinatar poate fi aflată de către expeditor printr-un mesaj primit de la clasele intermediare. ConcreteObserver apelează operaţia GetState a subiectului pentru a-şi actualiza informaţi privind starea subiectului.clasele intermediare pot alege destinatarii. 16 .o cerere poate fi procesată de mai mulţi destinatari.3. folosindu-se în acest sens clase intermediare.

Pentru fiecare rol mentionat mai sus se crează o clasă Functie (cu rolul de ConcreteHandler). 8. } E ca un fel de aruncarea mâţei moarte în ograda vecinului în funcţie de starea de putrefacţie a bietului animal. 17 .17 Exemplu de utilizare a şablonului lanţ de responsabilităţi Fiecare clasă Funcţie va implementa metoda proceseazăDosarCredit. şef de filială sau sucursală şi în rare cazuri un credit are nevoie şi de aprobarea managerilor din centrală. Fig. 8. în care există un atribut ce ne indică limita creditului ce poate fi aprobat fără a fi trimis şi la nivelul ierarhic superior.suma <= limitaCredit ) { //procesează efectiv dosarul în sensul aprobării sau respingerii lui } else if ( superior != null ) superior.Fig. manager al departamentului de credite. proceseazaDosarCredit(c). în mod asemănător cu codul următor: public void proceseazaDosarCredit( Credit c ) { if ( c. Cu cât starea de putrefacţie este mai mare cu atât pisica va ajunge la un vecin mai îndepărtat (în speranţa că toţi vecinii vor păstra aceeaşi direcţie). Aprobarea unui credit poate fi făcută la nivelul unui ofiţer de credit.16 Şablonul lanţ de responsabilităţi Un exemplu de astfel de şablon este modul de autorizare a unor tranzacţii de către anumiţi angajaţi în funcţie de mărimea acestor tranzacţii.

3. Şablonul conţine un grup de algoritmi. 8. În acest şablon se foloseşte o clasă de amintire (Memento) ce conţine aceleaşi proprietăţi de stare ca şi clasa obiectelor de salvat (Originator).setMemento(caretaker.createMemento()).5 Strategie Şablonul strategie ne ajută să alegem un anumit algoritm de utilizat în funcţie de un context.8. iar obiectul memento astfel obţinut ar fi folosit ca parametru de intrare în metoda addMemento din Caretaker: caretaker.3. 8. în condiţiile în care se ştie un anumit număr de ordine al acesteia în cadrul colecţiei de stări: originator. Revenirea la o stare anterioară.4 Memento (Amintire) Şablonul amintire (memento) este un şablon comportamental destinat salvării diferitelor stări curente ale unor obiecte şi revenirea la aceste stări.addMemento(originator. 18 .18 Şablonul memento Clientul care ar folosi un astfel de şablon ar începe prin utilizarea metodei createMemento din Originator. fiecare din aceştia fiind încapsulat într-un obiect. Obiectele de amintire se pot gestiona eventual într-o colecţie (Caretaker).getMemento(7)). Clienţii ce folosesc algoritmii nu depind de aceştia. variind în mod independent. Obiectul de salvat trebuie să conţină câte o metodă pentru fiecare din aceste două acţiuni: salvare (createMemento) şi revenire la stare anterioară (setMemento). Fig.

20 Şablonul iterator 19 . ci specific contextului în care rulează. 8. In orice moment unul din elementele colecţiei este considerat ca fiind elementul curent.19 Şablonul strategie Obiectele de tip context conţin câte un obiect strategy. 8.Fig. Fig.3. dar alegerea unei strategii concrete se realizează în funcţie de context. fără a ne folosi de caracteristicile acestor elemente.6 Şablonul iterator Şablonul iterator este folosit pentru a accesa elementele unui agregat (a unei colecţii) în mod secvenţial. Conform şablonului strategy comportamentul unei clase nu ar trebui să fie moştenit. 8.

8. 8. . Dacă se pleacă de la o expresie corectă la sfărşitul parcurgerii acesteia în stiva utilizată va rămâne o singură valoare. stive). .first.isLast.hasPrevious. liste.currentItem (ghici ce face fiecare operaţie). . Tot evaluatorul trebuie să parcurgă fiecare parte a expresiei: . . Conform şablonului interpreter atât operanzii.20 Şablonul interpreter Diagrama claselor de mai sus (cea din NetBeans de la acest şablon) nu surprinde nevoia existenţei unui evaluator de expresii.next. ea fiind chiar rezultatul interpretării. Acest evaluator trebuie să împartă expresia de interpretat în mai multe părţi cu un parser.isFirst. 20 .last.7 Şablonul interpreter Şablonul interpreter descrie cum se pot interpreta expresiile într-un anumit limbaj.Operaţii ale elementelor colecţiei de parcurs ar putea fi: . . . cât şi operatorii dintr-o expresie ar trebui să aibă aceeaşi interfaţă. Fig.previous. Şablonul iterator are un grad mai mare de importanţă în mediile de dezvoltare în care nu sunt implementate complet tipuri de date compuse (vectori.3.când întâlneşte un operator extrage din stivă valorile operanzilor afectaţi şi introduce în loc rezultatul aplicării operatorului asupra operanzilor.când întâlneşte un operand (o variabilă pe care are voie utilizatorul să o folosească într-o anumită formulă) îl introduce într-o stivă.hasNext. . . El îşi găseşte utilitatea în aplicaţiile economice în care se doreşte salvarea unor formule de calcul într-un format accesibil utilizatorilor finali şi folosirea ulterioară de către aplicaţie a acestor formule. .

ScriptEngine. obiectul ce deţine metoda şi valorile de transmis parametrilor.ScriptEngineManager. cum ar fi: numele metodei de apelat. .script. Obiectul receiver este cel care va efectua o acţiune ca urmare a lansării în execuţie a comenzii.eval("Expresia JavaScript de evaluat!").aplicaţii de interpretare a unui dialect SQL sau de traducere dintr-un dialect SQL în altul. Cum nu trebuie să „reinventăm roata” putem folosi interpretore deja existente.Exemple de aplicaţii în care ar putea fi utilizat şablonul interpreter: .21 Şablonul command Clientul instanţiază obiectul de tip comandă şi îl pregăteşte pentru a fi apelat la un moment ulterior. Beneficiile acestui şablon ţin de faptul că execuţia unei anumite metode poate fi pregătită din timp. try { Object result = jsEngine. } catch (ScriptException ex) { // tratarea excetiilor } 8. Un interpretor poate fi văzut şi ca o „cutie neagră” căreia i se dă o expresie şi care returnează un rezultat. 8.getEngineByName("JavaScript"). obiectul de care aparţine şi momentul exact al execuţiei.3. ScriptEngine jsEngine = mgr.aplicaţii de salarizare.aplicaţii de procesare a datelor la importul sau exportul lor din diferite sisteme. Fig. import javax. Şablonul command poate fi utilizat pentru a realiza aplicaţii cu: 21 .script. Obiectul invoker decide când va fi apelat obiectul comandă. .8 Şablonul command Conform şablonului command un obiect poate încapsula toate informaţiile necesare pentru apelarea unei metode a altui obiect. în aşa fel încât aceasta să fie lansată fără să i se ştie numele. ScriptEngineManager mgr = new ScriptEngineManager(). cum ar fi cele pentru scripturi: import javax.

. 22 . .funcţionalităţi de tip „wizard”.înregistrări de macro-uri.comportament tranzacţional.funcţionalităţi de tip „undo”. iar acesta îi transmite păpuşii să ţopăie (metoda action din şablon). De exemplu. . dacă un păpuşar (client) doreşte să pună o păpuşă (receiver) să se bucure (concretecommand) foloseşte un invoker.progress bar sincronizat cu execuţia unui grup de comenzi. . .

Sign up to vote on this title
UsefulNot useful