Definitie
Este sablonul care descrie crearea unor obiecte in regim pas cu pas, in conditiile in care procesul de creare este independent de structura interna a obiectelor.
Context
Sa presupunem ca un anumit editor (de ex. Word) trebuie sa poate converti un document in mai multe formate de reprezentare, ca: ASCII, HTML, TeX etc.
Problema care apare aici este aceea ca numarul de reprezentari posibile nu este limitat si trebuie ca adaugarea unui nou tip de conversie sa nu afecteze restul editorului.
Sablonul Builder propune ca solutie definirea unei clase DocReader care va baleia documentul de convertit si a unei clase DocConverter care realizeaza conversia fiecarei unitati (caractere, specificatii de formatare etc) a documentului.
Unui obiect DocReader i se va asocia la un moment dat un obiect apartinand unei subclase a luiDocConverter. Fiecare subclasa a lui DocConverter corespunde unui anumit tip de conversie.
Motivatii
Sablonul Builder se aplica in situatiile in care:
algoritmul de creare a unui obiect complex trebuie sa fie independent de partile ce compun obiectul;
procesul de construire trebuie sa permita reprezentari diverse pentru obiectul implicat.
Solutie
In figura de mai jos este data structura de clase care constituie sablonul Builder:
Consecinte
Sablonul Builder:
permite schimbarea reprezentarii interne pentru produs. Deoarece construirea produsului se face via o interfata abstracta (Builder), daca se doreste la un moment dat sa se treaca la o alta reprezentare interna, trebuie doar sa se asocieze Director-ul cu un alt obiect ConcreteBuilder;Implementare
izoleaza codul aferent construirii si reprezentarii. Aici este vorba de o aplicare a principiului modularitatii, prin faptul ca se incapsuleaza (in obiectele ConcreteBuilder) modul in care un obiect este construit si reprezentat. Clientii nu trebuie sa stie nimic despre clasele care definesc structura interna a produsului. Aceste clase nu apar in interfata Builder. Fiecare ConcreteBuilder contine intregul cod pentru a crea si asambla un anumit produs particular. Mai multe obiecte Director diferite pot reutiliza codul respectiv pentru a crea produse;
permite un control mai adanc asupra procesului de construire. Spre deosebire de alte sabloane creationale, care construiesc produsele "dintr-un foc", sablonul Builder construieste produsul pas cu pas, sub controlul obiectului Director. Doar cand produsul este gata, el poate fi obtinut de la constructor. Interfata Builder reflecta procesul de constructie mai in detaliu decat celelalte sabloane creationale.
Interfata Builder trebuie sa prevada cate o operatie pentru fiecare componenta a produsului. In mod implicit aceste operatii nu fac nimic, urmand a fi redefinite de fiecare ConcreteBuilder dupa necesitati.O problema importanta la acest sablon o constituie definirea modului de asamblare a componentelor produsului. In principiu exista 2 moduri de asamblare:
- partile componente sunt pur si simplu adaugate la "coada" produsului aflat in constructie (ca in cazul exemplului prezentat la inceputul capitolului);
- unele parti trebuie inserate la "mijlocul" produsului, intre componente create si atasate anterior. De exemplu, la construirea unui labirint de incaperi este necesar sa se prevada usi intre 2 camere vecine. In acest caz trebuie sa existe o comunicare bilaterala intre Builder si director, in sensul ca Builder-ul returneaza uneori referinte ale unor componente create, referinte pe care apoi directorul le va pasa ca parametri Builder-ului, cand il va solicita sa construiasca o noua componenta legata de cele anterioare.
Dupa cum se observa din diagrama sablonului, nu exista o interfata comuna pentru produse. In practica, aceste produse sunt foarte diferite intre ele ca reprezentare, astfel incat nu s-ar justifica existenta unei clase parinte comune. In mod normal, clientul care ataseaza unui Director un ConcreteBuilder stie exact care este acel ConcreteBuilder si ce fel de produs creaza el.
Daca la implementare se utilizeaza limbajul C++, nu se recomanda ca metodele din Builder sa fie pur virtuale, deoarece clasele ConcreteBuilder trebuie lasate sa redefinesca doar acele metode de care au nevoie pentru a crea un anumit produs. De exemplu, cand un document este convertit in format ASCII, se vor prelucra doar caracterele de text propriu-zis, nu si specificatiile de "decorare" a textului sau de punere in pagina.
Definitie
Creaza premizele ca o anumita clasa sa fie instantiata doar o singura data, permitandu-se un acces global la instanta respectiva.
Context
Exista situatii cand un anumit obiect trebuie sa existe doar intr-un singur exemplar. Spre exemplu, intr-o aplicatie gen File Manager, arborele director trebuie sa fie unul singur, orice modificare trebuind sa se reflecte in acest unic obiect.
Un alt exemplu, mai familiar poate, este legat de tema de la lucrarea de laborator Factory Method. Acolo, unul dintre grupurile de produsele concrete a fost CalculeStatistice. In cazul in care se doreste ca toate calculele sa se refere la acelasi vector de valori, se poate impune ca vectorul sa fie reprezentat printr-un obiect unic.
O posibilitate ar fi utilizarea variabilelor globale. Aceastea pot fi accesate de mai multi clienti, dar nu pot opri instantierea clasei respective de mai multe ori. Ca urmare, se impune o solutie prin care clasa insasi sa fie responsabila de crearea instantei unice si de oferirea accesului la ea. Aceasta solutie o constituie sablonul Singleton.
Motivatii
Sablonul Singleton se aplica in situatiile in care:
trebuie ca pentru o anumita clasa sa existe doar o singura instanta si aceasta trebuie sa fie accesibila clientilor dintr-un punct de acces cunoscut;
instanta unica a unei clase trebuie sa poata fi extinsa prin derivare, iar clientii sa poata utiliza instanta extinsa fara a-si modifica propriul cod..
Solutie
In figura de mai jos este data structura de clase care constituie sablonul Singleton:
Consecinte
Sablonul Singleton are urmatoarele avantaje:
controleaza accesul la instanta unica, deoarece clasa Singleton incapsuleaza propria instanta;Implementare
conduce la reducerea spatiului de nume, deoarece nu implica folosirea variabilelor globale;
permite detalierea operatiilor si a reprezentarilor. Clasa Singleton poate fi derivata si este usor sa se configureze o aplicatie cu o instanta a clasei derivate;
poate fi adaptat pentru a se crea nu doar o singura instanta, ci un numar oarecare fixat, pastrandu-se mereu controlul asupra acestui numar. Pentru aceasta este necesar sa se modifice doar operatia Instance;
asigura o flexibilitate mai mare decat daca s-ar utiliza metode statice. O alternativa la sablonul Singleton ar fi fost ca toate functiunile clasei Singleton sa fie realizate cu ajutorul unor metode statice (practic in acest caz am fi avut de a face cu 0 instante, nu cu una). Dezavantajele ar fi ca:
- solutia nu poate fi adaptata pentru situatia in care dorim 'n' instante in loc de 1;
- metodele statice nu pot fi virtuale, deci nu pot fi redefinite in subclase pentru a putea beneficia de polimorfism.
Asigurarea unicitatii instantei. O posibilitate in acest sens este de a ascunde operatia care creaza instante (constructorii) in spatele unei metode statice care poate garanta numarul de instante create. Aceasta metoda are acces la o variabila care contine sau care refera instanta si are grija sa initializeze variabila respectiva inainte de a o returna clientilor.Se observa ca singura posibilitate pentru clienti de a obtine acces la instanta clasei Singleton este apelul metodei Instance. Orice tentativa de a crea direct o instanta se va solda cu eroare la compilare deoarece constructorul este protected.
class Singleton {
public:
static Singleton* Instance();
protected:
//alte metode accesibile clientilorSingleton();
private:static Singleton* _instance;
};
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance(){if(_instance==0) _instance=new Singleton;
}
return _instance;