You are on page 1of 44

Chain of Responsibility Tip i scop: ablon comportamental; evit dependen a unui emi tor de un anumit receptor cu ajutorul unei

colec ii de receptori (ce ar putea fiecare gestiona o cerere); Solu ie: se construie te un lan (pipeline) de noduri ce pot gestiona o cerere; emi torul lanseaz cererea (launch-and-leave); cererea este pasat din nod n nod pan cnd un anumit nod o gestioneaz ;

Exemplu:
#include <iostream> #include <vector> #include <string> #include <ctime> using namespace std; class Base { Base* nextLink; public: Base() : nextLink(NULL) {} void setNext(Base* link){ nextLink = link; } void addLink(Base* link) { if ( nextLink != NULL ) { nextLink->addLink(link); } else { nextLink = link; } } // the "chain" method in the base class always delegates to the next obj virtual void handleRequest(const string& request) { nextLink->handleRequest(request); }

}; class Handler1: public Base { public: /*virtual*/ void handleRequest( const string& request) { // don't handle requests 3 times out of 4 if ( rand() % 3 ) { cout << "Handler1 passsed ..."; // delegate to the base class Base::handleRequest(request); } else { cout << "Handler1 handled " << request << "\n"; } } }; class Handler2: public Base { public: /*virtual*/ void handleRequest(const string& request) { if ( rand() % 3 ) { cout << "Handler2 passsed ..."; Base::handleRequest(request); } else { cout << "Handler2 handled " << request << "\n"; } } }; class Handler3: public Base { public: /*virtual*/ void handleRequest(const string& request) { if ( rand() % 3 ) { cout << "Handler3 passsed ..."; Base::handleRequest(request); } else { cout << "Handler3 handled " << request << "\n"; } } }; int main() { srand(time(0)); Handler1 root; Handler2 two; root.addLink(&two); Handler3 thr; root.addLink(&thr); thr.setNext(&root); root.handleRequest("doThis"); root.handleRequest("doThat"); root.handleRequest("doAnotherThing"); root.handleRequest("doSomething"); root.handleRequest("doAnything"); return 0; }

Subject-Observer Tip i scop: ablon comportamental; define te o dependen de tip one-to-many ntre obiecte, a.. atunci cnd un obiect i schimb starea, obiectele dependente sunt notificate automat despre acest fapt; Solu ie: un obiect Subject gestioneaz o colec ie de obiecte Observer; atunci cnd sunt create, obiectele Observer trebuie s se nregistreze la obiectul Subject; acesta include noul obiect Observer n colec ia sa; atunci cnd obiectul Subject i schimb starea, el informeaz n mod automat toate obiectele Observer aflate n colec ia sa;

Participan i: Subject: interfa pentru nregistrarea observatorilor i notificarea lor automat atunci cnd se schimb starea; Observer: declararea interfe ei unui observator (metoda virtual notify() ); ConcreteObserverA, ConcreteObserverB: implementarea interfe ei de observator (modul specific n care acesta reac ioneaz anunci cnd subiectul i schimb starea); Exemplu:
#include <iostream> #include <vector> using namespace std; // observer interface class IAlarmListener { public: virtual void alarm() = 0; }; // subject class SensorSystem

// modul in care trebuie sa reactioneze dispozitivul la declansarea alarmei

{ vector < IAlarmListener* > listeners; public: void attach( IAlarmListener* al) { listeners.push_back(al); } // notify all void soundTheAlarm() { cout << "ALARM!" << endl; int nSize = listeners.size(); for (int i = 0; i < nSize; ++i) listeners[i]->alarm(); } }; // specific observer class Lighting: public IAlarmListener { public: /*virtual*/ void alarm() { cout << "Lights up!" << endl; } }; // another specific observer class Gates: public IAlarmListener { public: /*virtual*/ void alarm() { cout << "Gates close!" << endl; } }; int main() { SensorSystem ss; ss.attach( &Gates() ); ss.attach( &Lighting() ); ss.soundTheAlarm(); return 0; } // colectia de dispozitive

Strategy Tip i scop: ablon comportamental; define te o familie de algoritmi ce pot fi utiliza i unul n locul celuilat; Solu ie: un algoritm este ncapsulat ntr-o ierarhie de clase; clien ii de in doar o referin c tre clasa de baz ; variata aleas depinde de factori (context) cunoscu i doar la execu ie (run-time);

Exemplu:
#include <iostream> #include <fstream> #include <string> using namespace std; enum { nWordWidth = 50, nLineWidth = 200 }; enum { Left=1, Right, Center }; class IStrategy { public: IStrategy(int width): _width(width){} void format() { ifstream inFile("quote.txt", ios::in); char line[nLineWidth], word[nWordWidth]; line[0] = '\0'; inFile >> word; strcat(line, word); while (inFile >> word) { if ( (strlen(line) + strlen(word) + 1) > _width) { justify(line); } else strcat(line, " "); strcat(line, word); } justify(line); } protected: int _width;

private: virtual void justify(char* line) = 0; }; class LeftStrategy: public IStrategy { public: LeftStrategy(int width): IStrategy(width){} private: /* virtual */ void justify(char* line) { // show the line cout << line << endl; // make clean line[0] = '\0'; } }; class RightStrategy: public IStrategy { public: RightStrategy(int width): IStrategy(width){} private: /* virtual */ void justify(char* line) { char buf[nLineWidth]; // show spaces, then the line int offset = _width - strlen(line); memset(buf, ' ', nLineWidth); strcpy(&(buf[offset]), line); cout << buf << endl; // make clean line[0] = '\0'; } }; class CenterStrategy: public IStrategy { public: CenterStrategy(int width): IStrategy(width){} private: /* virtual */ void justify(char* line) { char buf[nLineWidth]; // show the line between spaces int offset = (_width - strlen(line)) / 2; memset(buf, ' ', nLineWidth); strcpy(&(buf[offset]), line); cout << buf << endl; // make clean line[0] = '\0'; } }; class Test { public: Test () : _strategy(NULL) {} void setStrategy(int type, int width); void doIt() { _strategy->format(); } private: IStrategy* _strategy; };

void Test::setStrategy(int type, int width) { delete _strategy; switch (type) { default : case Left : _strategy = new LeftStrategy(width); break; case Right : _strategy = new RightStrategy(width);break; case Center : _strategy = new CenterStrategy(width); break; } } int main() { Test test; int answer, width; cout << "Exit(0) Left(1) Right(2) Center(3): "; cin >> answer; while (answer) { cout << "Width: "; cin >> width; test.setStrategy(answer, width); test.doIt(); cout << "Exit(0) Left(1) Right(2) Center(3): "; cin >> answer; } return 0; }

Template Method Tip i scop: ablon comportamental; define te pa ii unui algoritm, l snd clasele client sa rafineze ace ti pa i; Solu ie: proiectantul decide care pa i sunt invarian i (standard) i care sunt variabili (personalizabili); pa ii invarian i sunt implementa i n clasele de baz ; pa ii variabili nu sunt implementa i sau li se ofer o implementare implicit ;

Exemplu:
#include <iostream> using namespace std; class Base { // Invariant steps void a() { cout << "a "; } void c() { cout << "c "; } void e() { cout << "e "; } // Steps requiring peculiar implementations are "placeholders" in base class virtual void ph1() = 0; virtual void ph2() = 0; public: // Standardize the skeleton of an algorithm in a base class "template method" void execute() { a(); ph1(); c(); ph2(); e(); } }; // Derived classes implement placeholder methods class One: public Base { /*virtual*/void ph1() { cout << "b "; } /*virtual*/void ph2() { cout << "d "; } };

class Two: public Base { /*virtual*/void ph1() { cout << "2 "; } /*virtual*/void ph2() { cout << "4 "; } }; int main() { Base* array[] = { &One(), &Two() }; for (int i = 0; i < 2; i++) { array[i]->execute(); cout << '\n'; } system("pause"); return 0; }

Visitor Tip i scop: ablon comportamental; permite definirea de noi opera ii pe o structur , f a modifica (polua) clasele componente i f a interoga tipul obiectului din structur ; Solu ie: opera ia executat depinde de tipul celor dou obiecte implicate (double dispatch): vizitatorul i obiectul vizitat; ierarhia Visitor defineste o metod virtual pur Visit() pentru fiecare tip concret din ierarhia int , Element; fiecare metod Visit() posed un argument de tip referin c tre un obiect Element; ierarhia Element define te o metod virtual Accept(), metod ce posed un argument de tip referin c tre Visitor;

Exemplu:
#include <iostream> #include <string> using namespace std; class IVisitor; // add an "accept" method to the "element" hierarchy class IElement { public: virtual void Accept( IVisitor& visitor) = 0; }; class This: public IElement { public: /*virtual*/ void Accept( IVisitor& visitor ); string thiss() { return "This"; } }; class That: public IElement { public: /*virtual*/void Accept( IVisitor& visitor ); string that() { return "That"; }

}; class TheOther: public IElement { public: /*virtual*/void Accept( IVisitor& visitor ); string theOther() { return "TheOther"; } }; // create a "visitor" base class with a "visit" method for every "element" type class IVisitor { public: virtual void Visit(This* element) = 0; virtual void Visit(That* element) = 0; virtual void Visit(TheOther* element) = 0; }; /*virtual*/ void This::Accept(IVisitor& visitor) { visitor.Visit(this); } /*virtual*/ void That::Accept(IVisitor& visitor) { visitor.Visit(this); } /*virtual*/ void TheOther::Accept(IVisitor& visitor) { visitor.Visit(this); } // create a "visitor" derived class for each "operation" to do on "elements" class UpVisitor: public IVisitor { /*virtual*/ void Visit(This* element) { cout << "do Up on " + element->thiss() << '\n'; } /*virtual*/ void Visit(That* element) { cout << "do Up on " + element->that() << '\n'; } /*virtual*/ void Visit(TheOther* element) { cout << "do Up on " + element->theOther() << '\n'; } }; class DownVisitor: public IVisitor { /*virtual*/ void Visit(This* element) { cout << "do Down on " + element->thiss() << '\n'; } /*virtual*/ void Visit(That* element) { cout << "do Down on " + element->that() << '\n'; } /*virtual*/ void Visit(TheOther* element) { cout << "do Down on " + element->theOther() << '\n'; } }; int main() { // make the structure IElement* list[] = { new This(), new That(), new TheOther() }; // "visitor" objects UpVisitor up; DownVisitor down; for (int i = 0; i < 3; ++i) list[i]->Accept(up);

for (i = 0; i < 3; ++i) list[i]->Accept(down); return 0; }

Abstract Factory Tip i scop: ablon crea ional; crearea de familii de obiecte nrudite/dependente, obiecte ce trebuie utilizate mpreun ; Probleme ntmpinate la crearea unui nou obiect: complexitate sporit (procesul nu se reduce la simpla creare a unui nou obiect): o clasa (tipul) obiectului poate fi creeat dinamic; o obiectul poate fi returnat dintr-un object pool; o obiectul poate fi configurat n diverse moduri; duplicarea codului surs ; informa ii neaccesibile noului obiect; centralizarea managementului duratei de via a obiectelor pentru a asigura un comportament consistent; abstractizare insuficient ; Factory: abstractizarea conceptului de obiect responsabil pentru crearea altor obiecte (produse). Solu ie: cte un Factory responsabil pentru crearea unui tip de obiect (produs); un Abstract Factory incapsuleaz un grup de Factory ce au o tem comun ;

Participan i: AbstractFactory: declararea interfe ei pentru opera iile de creare de obiecte; ConcreteFactory1: ConcreteFactory2: implementarea opera iilor pentru crearea de obiecte; AbstractProductA AbstractProductB: interfe ele obiectelor ce vor fi create;

ProductA1 ProductB1: obiectele create de c tre fabrica concret ConcreteFactory1; ProductA2 ProductB2: obiectele create de c tre fabrica concret ConcreteFactory2; Exemplu:
#include <iostream> using namespace std; // AbstractProductA struct ICarTrip { }; class BusinessCarTrip : public ICarTrip { public: BusinessCarTrip() { cout << "Luxury travel with a car" << endl; } }; class EconomicCarTrip : public ICarTrip { public: EconomicCarTrip() { cout << "Economic travel with a car" << endl; } }; // AbstractProductB struct IAirplaneTrip { }; class BusinessAirplaneTrip : public IAirplaneTrip { public: BusinessAirplaneTrip() { cout << "Luxury travel with an airplane" << endl; } }; class EconomicAirplaneTrip : public IAirplaneTrip { public: EconomicAirplaneTrip() { cout << "Economic travel with an airplane" << endl; } }; // AbstractFactory class ITripFactory { public: virtual ICarTrip* makeCarTrip() = 0; virtual IAirplaneTrip* makeAirplaneTrip() = 0; }; // ConcreteFactory1 class BussinesTripFactory : public ITripFactory { public: ICarTrip* makeCarTrip() { return new BusinessCarTrip;

} IAirplaneTrip* makeAirplaneTrip() { return new BusinessAirplaneTrip; } }; // ConcreteFactory2 class EconomicTripFactory : public ITripFactory { public: ICarTrip* makeCarTrip() { return new EconomicCarTrip; } IAirplaneTrip* makeAirplaneTrip() { return new EconomicAirplaneTrip; } };

int main() { cout << "Show me the money: "; int nMoney; cin >> nMoney; if ( nMoney < 100 ) { cout << "You do not go anywhere!" << endl; return 0; } ICarTrip* carTrip; IAirplaneTrip* airplaneTrip; ITripFactory* tripFactory; if ( nMoney < 1000 ) { tripFactory = new EconomicTripFactory; } else { tripFactory = new BussinesTripFactory; } carTrip = tripFactory->makeCarTrip(); airplaneTrip = tripFactory->makeAirplaneTrip(); return 0; }

Observa ii: Deoarece produsele sunt precizate n interfa a de AbstractFactory, ad ugarea de noi produse este dificil , presupunnd modificarea tuturor versiunilor de ConcreteFactory; Schimbarea tipului de ConcreteFactory (n punctul de instan iere), conduce la schimbarea unei ntregi familii de produse.

Builder Tip i scop: ablon crea ional; abstractizeaz pa ii n construc ia unui obiect, a.. diferite implement ri ale acestor pa i s rezulte n diverse versiuni ale obiectului; Probleme ntmpinate la crearea unui nou obiect: complexitate sporit (procesul nu se reduce la simpla creare a unui nou obiect): o clasa (tipul) obiectului poate fi creeat dinamic; o obiectul poate fi returnat dintr-un object pool; o obiectul poate fi configurat n diverse moduri; duplicarea codului surs ; informa ii neaccesibile noului obiect; centralizarea managementului duratei de via a obiectelor pentru a asigura un comportament consistent; abstractizare insuficient ; Builder: abstractizarea conceptului de obiect responsabil pentru crearea altor obiecte (produse). Solu ie: un Builder este responsabil pentru crearea unui versiuni de obiect (produs), i spunde la comenzile unui Director; un Director manageriaz un Builder; clientul instan iaz un Director i i asociaz un Builder corespunz tor cerin elor sale;

Participan i: Builder: declararea interfe ei pentru pa ii implica i n crearea unui obiect; ConcreteBuilder: implementarea pa ilor implica i n crearea unui obiect;

Director: construie te un obiect prin intermediul unui ConcreteBuilder; Product: obiectul final, construit la solicitarea unui Director, de c tre un ConcreteBuilder; Exemplu:
#include <vector> #include <algorithm> #include <string> #include <iostream> using namespace std; // Product class PizzaNapoletana { static void printString(string s) { cout << s << " "; } protected: vector<string> ingredients; string name; public: void printIngredients() { cout << name << endl; cout << "Ingredients: "; for_each( ingredients.begin(), ingredients.end(), printString); cout << endl; } void setName( const string& name ) { this->name = name; } void addCheese(const string& cheese) { ingredients.push_back( cheese ); } void addTomatoes( const string& tomatoes ) { ingredients.push_back(tomatoes); } void addOil( const string& oil ) { ingredients.push_back(oil); } void addBasil() { ingredients.push_back("basil"); } void addGarlic() { ingredients.push_back("garlic"); } void addOregano() { ingredients.push_back("oregano"); } void addOlives() { ingredients.push_back("olives"); } };

// Builder class IPizzaNapoletanaRecipe { protected: PizzaNapoletana* pizza; public: PizzaNapoletana* getPizza() { return pizza; } // abstract steps to make pizza virtual void createNewPizza() = 0; virtual void putCheese() = 0; virtual void putTomatoes() = 0; virtual void putOil() = 0; virtual void putBasil() = 0; virtual void putGarlic() = 0; virtual void putOregano() = 0; virtual void putOlives() = 0; }; // ConcreteBuilder class MarguerittaRecipe : public IPizzaNapoletanaRecipe { public: void createNewPizza() { pizza = new PizzaNapoletana; pizza->setName("Margueritta"); } void putCheese() { pizza->addCheese("sliced mozzarella"); } void putTomatoes() { pizza->addTomatoes("San Marzano tomatoes"); } void putOil() { pizza->addOil("olive oil"); } void putBasil() { pizza->addBasil(); } void putGarlic() { return; } void putOregano() { return; } void putOlives() { return; } }; // ConcreteBuilder class MarinaraRecipe : public IPizzaNapoletanaRecipe { public: void createNewPizza()

{ pizza = new PizzaNapoletana; pizza->setName("Marinara"); } void putCheese() { pizza->addCheese("mozzarella"); } void putTomatoes() { pizza->addTomatoes("tomatoes"); } void putOil() { pizza->addOil("olive oil"); } void putBasil() { return; } void putGarlic() { pizza->addGarlic(); } void putOregano() { pizza->addOregano(); } void putOlives() { pizza->addOlives(); } }; // Director class Chef { IPizzaNapoletanaRecipe* pizzaRecipe; public: Chef() { pizzaRecipe = NULL; } void setPizzaRecipe(IPizzaNapoletanaRecipe* pizzaRecipe) { this->pizzaRecipe = pizzaRecipe; } PizzaNapoletana* cookPizza() { if ( NULL == pizzaRecipe ) { cout << "No recipe associated! " << endl; return NULL; } // manage the steps to cook pizza pizzaRecipe->createNewPizza(); pizzaRecipe->putCheese(); pizzaRecipe->putTomatoes(); pizzaRecipe->putOil(); pizzaRecipe->putBasil(); pizzaRecipe->putGarlic(); pizzaRecipe->putOregano(); pizzaRecipe->putOlives(); return pizzaRecipe->getPizza(); }

}; int main() { // director Chef someChef; // try make pizza PizzaNapoletana* pizza0 = someChef.cookPizza(); if ( NULL != pizza0 ) { pizza0->printIngredients(); } // set new builder MarguerittaRecipe pizzaRecipe1; someChef.setPizzaRecipe( &pizzaRecipe1 ); // make pizza PizzaNapoletana* pizza1 = someChef.cookPizza(); pizza1->printIngredients(); // set new builder MarinaraRecipe pizzaRecipe2; someChef.setPizzaRecipe( &pizzaRecipe2 ); // make pizza PizzaNapoletana* pizza2 = someChef.cookPizza(); pizza2->printIngredients(); return 0; }

Factory Method Tip i scop: ablon crea ional; crearea de obiecte f

a preciza exact tipul acestora.

Probleme ntmpinate la crearea unui nou obiect: complexitate sporit (procesul nu se reduce la simpla creare a unui nou obiect): o clasa (tipul) obiectului poate fi creeat dinamic; o obiectul poate fi returnat dintr-un object pool; o obiectul poate fi configurat n diverse moduri; duplicarea codului surs ; informa ii neaccesibile noului obiect; centralizarea managementului duratei de via a obiectelor pentru a asigura un comportament consistent; abstractizare insuficient ; Factory: abstractizarea conceptului de obiect responsabil pentru crearea altor obiecte (produse). Solu ie: cte o metod Factory responsabil pentru crearea unui tip de obiect (produs); metoda Factory poate fi parametrizat , pentru a putea crea mai multe tipuri concrete de produse care implementeaz o aceea i interfa ; metoda Factory poate fi supranc rcat n clasele derivate, pentru a crea o anumit versiune a respectivului produs.

Participan i: Product: define te interfa a obiectului ce va fi creat; ConcreteProduct1: ConcreteProduct2: diverse versiuni (concretiz ri) ale obiectului ce va fi creat; Creator: define te o metod ce returneaz un obiect de tipul Product;

ConcreteCreator1: ConcreteCreator2: suprascrie metoda pentru a returna versiunea dorit obiectului Product. Exemplu:
#include <vector> #include <map> #include <algorithm> #include <string> #include <iostream> using namespace std; // Product class IPizzaNapoletana { public: virtual string name() = 0; void printIngredients() { cout << "Ingredients: "; for_each( ingredients.begin(), ingredients.end(), printString); cout << endl; } protected: vector<string> ingredients; IPizzaNapoletana() { ingredients.push_back("mozzarella"); ingredients.push_back("tomatoes"); } private: static void printString(string s) { cout << s << " "; } }; enum {MarguerittaID, MarinaraID, UnknownPizzaID }; // ConcreteProduct1 class Margueritta : public IPizzaNapoletana { public: Margueritta() { ingredients.push_back("basil"); ingredients.push_back("olive oil"); } string name() { return string("Margueritta"); } }; // ConcreteProduct2 class Marinara : public IPizzaNapoletana { public: Marinara() { ingredients.push_back("olive oil"); ingredients.push_back("garlic"); ingredients.push_back("oregano"); } string name() { return string("Marinara"); } }; // auxiliary classes class IOwen

{ public: virtual void baking( IPizzaNapoletana*& ) = 0; }; class WoodBrickOven : public IOwen { public: void baking( IPizzaNapoletana*& pizza ) { cout << "Pizza " << pizza->name() << " was baked in a wood brick oven" << endl; } }; class ElectricDeckOven : public IOwen { public: void baking( IPizzaNapoletana*& pizza ) { cout << "Pizza " << pizza->name() << " was baked in an electric deck oven" << endl; } }; // Creator class IRestaurant { protected: // specific owen IOwen* pOwen; public: // factory method (default implementation) virtual IPizzaNapoletana* makePizza( int pizzaId ) = 0 { IPizzaNapoletana* tmpPizza = NULL; switch ( pizzaId ) { case MarguerittaID case MarinaraID }

: tmpPizza = new Margueritta; break; : tmpPizza = new Marinara; break;

if ( NULL == tmpPizza ) { cout << "Unknown pizza ID!" << endl; } else { cout << "Name: " << tmpPizza->name() << endl; tmpPizza->printIngredients(); } return tmpPizza; } }; // ConcreteCreator1 class Domneasca : public IRestaurant { map<int, int> pizzaPrice; public: Domneasca() { pOwen = new WoodBrickOven; pizzaPrice.insert( pair<int,int>( MarguerittaID, 22 ) ); pizzaPrice.insert( pair<int,int>( MarinaraID, 20 ) ); } // factory method (concrete implementation) IPizzaNapoletana* makePizza( int pizzaId ) { // use default implementation IPizzaNapoletana* tmpPizza = IRestaurant::makePizza( pizzaId );

if ( NULL != tmpPizza ) { // restaurant specific baking pOwen->baking(tmpPizza); // show me the money! cout << "Price: " << pizzaPrice.find(pizzaId)->second << endl; cout << endl; } return tmpPizza; } }; // ConcreteCreator2 class Hot : public IRestaurant { vector<int> pizzaPrice; public: Hot() { pOwen = new ElectricDeckOven; // Margueritta pizzaPrice.push_back( 28); // Marinara pizzaPrice.push_back( 24); } // factory method (concrete implementation) IPizzaNapoletana* makePizza( int pizzaId ) { // use default implementation IPizzaNapoletana* tmpPizza = IRestaurant::makePizza( pizzaId ); if ( NULL != tmpPizza ) { // restaurant specific baking pOwen->baking(tmpPizza); // show me the money! cout << "Price: " << pizzaPrice[pizzaId] << endl; cout << endl; } return tmpPizza; } }; int main() { Domneasca restaurant1; IPizzaNapoletana* pizza1 = restaurant1.makePizza( MarguerittaID ); IPizzaNapoletana* pizza2 = restaurant1.makePizza( MarinaraID ); Hot restaurant2; IPizzaNapoletana* pizza3 = restaurant2.makePizza( MarguerittaID ); IPizzaNapoletana* pizza4 = restaurant2.makePizza( MarinaraID ); IPizzaNapoletana* pizza5 = restaurant2.makePizza( UnknownPizzaID ); return 0; }

Prototype Tip i scop: ablon crea ional; evit crearea de noi obiecte prin intermediul operatorului new atunci cnd acest lucru este prohibitiv; Prototype: instan responsabil pentru crearea celorlalte obiecte prin clonare.

Participan i: Prototype: declararea interfe ei pentru clonare; ConcretePrototype: implementarea opera iei de clonare; Client: construie te un nou obiect cerndu-I prototipului s se cloneze; Exemplu:
#include <vector> #include <string> #include <iostream> using namespace std; enum pizzaID {MarguerittaID, MarinaraID, UnknownPizzaID }; // Product class IPizzaNapoletana { public: void printName() { cout << pizzaName << endl; } // client calls this public static member function when it needs an instance of an IPizzaNapoletana subclass static IPizzaNapoletana* Clone( pizzaID id) { int nPizzaTypes = prototypeCollection.size(); for (int i = 0; i < nPizzaTypes; ++i)

{ if ( prototypeCollection[i]->returnID() == id) { return prototypeCollection[i]->makeSpecificClone(); } } return NULL; } private: static vector<IPizzaNapoletana*> prototypeCollection; // addPrototype() saves each prototype object here protected: // each subclass of IPizzaNapoletana registers its prototype static void addPrototype(IPizzaNapoletana* pizza) { prototypeCollection.push_back( pizza ); } virtual pizzaID returnID() = 0; virtual IPizzaNapoletana* makeSpecificClone() = 0; string pizzaName; }; vector<IPizzaNapoletana*> IPizzaNapoletana::prototypeCollection; // ConcreteProduct1 class Margueritta : public IPizzaNapoletana { private: // this is subclass's prototype object // default ctor will be called, which registers it static Margueritta _objectMargueritta; // this is only called when the private static data member is inited Margueritta() { pizzaName = "Margueritta"; addPrototype(this); } protected: /*virtual*/ pizzaID returnID() { return MarguerittaID; } /*virtual*/ IPizzaNapoletana* makeSpecificClone() { // call copy constructor return new Margueritta( _objectMargueritta ); } }; // ConcreteProduct2 class Marinara : public IPizzaNapoletana { private: // this is subclass's prototype object // default ctor will be called, which registers it static Marinara _objectMarinara; // this is only called when the private static data member is inited Marinara() { pizzaName = "Marinara"; addPrototype(this); } protected: /*virtual*/ pizzaID returnID() {

return MarinaraID; } /*virtual*/ IPizzaNapoletana* makeSpecificClone() { return new Marinara( _objectMarinara ); } }; // register the prototypes Margueritta Margueritta::_objectMargueritta; Marinara Marinara::_objectMarinara; int main() { const int HOW_MANY__PIZZA = 5; pizzaID input[HOW_MANY__PIZZA] = { MarguerittaID, MarinaraID, MarinaraID, UnknownPizzaID, MarguerittaID }; IPizzaNapoletana* pizza[HOW_MANY__PIZZA]; // given an pizza ID, find the right prototype, and return a clone for (int i = 0; i < HOW_MANY__PIZZA; ++i) pizza[i] = IPizzaNapoletana::Clone(input[i]); // demonstrate that correct image objects have been cloned for (i = 0; i < HOW_MANY__PIZZA; ++i) { if ( NULL != pizza[i] ) { pizza[i]->printName(); } else { cout << "Bad pizza ID!" << endl; } } // free the dynamic memory for (i = 0; i < HOW_MANY__PIZZA; ++i) delete pizza[i]; return 0; }

Unified Modeling Language (UML) UML este o nota ie grafic utilizat pentru a descrie/modela concepte din software, pe trei nivele posibile: conceptual diagrame aflate n strns rela ie cu limbajul natural, utilizate pentru a descrie (concepte i abstrac ii) o preoblem la nivel uman; deoarece nu sunt supuse unor reguli semantice, n elesul lor poate fi ambiguu i interpretabil; specifica ie diagrame ce descriu o propunere de proiectare a software-ului (o solu ie la o problem ); respect reguli semantice, avnd drept scop transformarea acestei propuneri n cod surs ; implementare diagrame ce descriu un cod surs deja implementat. De ce s model m? Modelele sunt construite pentru a afla dac entitatea modelat (un avion, un pod, o cl dire, etc) va func iona! Aceasta nsemn c modelul trebuie s fie testabil. Nu exist ns criterii pentru a evalua diagramele UML (evaluare subiectiv ). consider m, de exemplu, afirma ia: A dog is an animal. La nivel conceptual, diagrama descrie dou dou entit i (Animal i Dog), conectate printr-o rela ie de generalizare. Un Animal este o generalizare pentru un Dog. Un Dog este un caz special de Animal. Nimic altceva nu se mai poate deduce din aceast diagram . La nivel de specifica ie sau de implementare, acest diagram are ns un n eles mai precis:
class Animal {}; class Dog : public Animal {};

Codul surs define te clasele Animal i Dog ca fiind interconectate printr-o rela ie de mo tenire; astfel, modelul descrie o parte din program. n UML exist 3 tipuri generale de diagrame: statice descriu structura logic (clase, obiecte i rela iile dintre ele) care nu se modific ; dinamice descriu felul n care entit ile software se modific n timpul execu iei; fizice descriu structura fizic nemodificabil a entit ilor software (fi iere surs , fi iere binare, biblioteci, fi iere de date) i rela iile dintre acestea.

Consider m urm torul program drept exemplu:


// // // // // constaints.h This is a "constraints" base class We need to place a requirement on a template parameter to ensure some facility will exist! For example: D must be derived from B

template <typename D, typename B> class IsDerivedFrom { // private static method, to be called only from default constructor static void Constraints(D* pDerived) { B* pBase = pDerived; // if this conversion works, // then D IsDerivedFrom B pBase = pDerived; // suppress warnings about unused variables... } // no one can instantiate this class directly protected: // c-tor IsDerivedFrom() { // p is pointer to function who receives D* and returns void // p is nitialized, but never called! void (*p)(D*) = Constraints; } }; // tamplate specialization // force it to fail in the case where B is void template<typename D> class IsDerivedFrom<D, void> { IsDerivedFrom() { char* p = (int*)0; /* error */ } }; #include "constraints.h" #include <string> #include <iostream> using namespace std; template <typename T> class IComparable { public: // return value: // negative: current instance precedes the (*pObject) object in the sort order // zero: current instance occurs in the same position in the sort order as the // (*pObject) object // positive: current instance follows the (*pObject) object in the sort order virtual int CompareTo(const T& object) = 0; }; // a "comparable" string class ComparableString : public string, public IComparable<ComparableString> { public: ComparableString(char* sir ) : string(sir){} ComparableString(string sir ) : string(sir){}

/*virtual*/ int CompareTo(const ComparableString& object) { // string already implements a "compare" method; // so, we will use it! return (static_cast<string*>(this))->compare(object); } }; template <typename K, typename T > class TreeMap : /*must ensure*/ IsDerivedFrom<K, IComparable<K> > { // inner class; implementation detail class TreeMapNode { private: enum Direction {LESS = 0, GREATER}; // current node K key; T value; // two sons TreeMapNode* nodes[2]; void AddSubNode(Direction d, const K& key, const T& value) { if ( NULL == nodes[d] ) { // make new son node nodes[d] = new TreeMapNode(key, value); } else { // update son node nodes[d]->Add(key, value); } } T* FindSubNodeForKey(Direction d, const K& key) { return nodes[d] == NULL ? NULL : nodes[d]->Find(key); } public: TreeMapNode(const K& someKey, const T& someValue) : key(someKey), value(someValue) { nodes[ Direction::LESS ] = NULL; nodes[ Direction::GREATER] = NULL; } ~TreeMapNode() { delete nodes[ Direction::LESS ]; delete nodes[ Direction::GREATER]; } Direction SelectSubNode(const K& key) { return ( (this->key).CompareTo(key) < 0) ? GREATER: LESS; } T* Find(const K& key) {

if ( (this->key).CompareTo(key) == 0) return new T(value); // more deep seeking return FindSubNodeForKey( SelectSubNode(key), key); } void Add(const K& key, const T& value) { if ( (this->key).CompareTo(key) == 0) { // set new value this->value = value; } else { // deep adding AddSubNode(SelectSubNode(key), key, value); } } }; // root node TreeMapNode* topNode; public: TreeMap() : topNode(NULL){} void Add(const K& key, const T& value) { // empty tree ? if ( NULL == topNode) { topNode = new TreeMapNode(key, value); } else { topNode->Add(key, value); } } T* Get(const K& key) { return (NULL == topNode) ? NULL : topNode->Find(key); } ~TreeMap() { delete topNode; } }; int main() { typedef TreeMap<ComparableString, string> dictionar; dictionar d; d.Add( ComparableString("oop"), string("method of developing software that models the real world using objects") ); d.Add( ComparableString("object"), string("self contained item of data that can only be accessed or changed in a controlled way") );

// starting point

d.Add( ComparableString("polymorphism"), string("many shapes") ); d.Add( ComparableString("virtual"), string("can be overridden in a derived class") ); d.Add( ComparableString("overridden"), string("different behaviour") ); cout << "Question == "; string question; cin >> question; string* answer = d.Get(ComparableString(question)); if (NULL != answer) { cout << question << " == " << *answer << endl; } else { cout << "I have no ideea what is " << question << "!" << endl; } delete answer; return 0; }

A. Diagrame de clase O diagram de clase descrie cele mai importante clase dintr-un program, precum i rela iile dintre acestea.

Astfel: clasa TreeMap posed metodele publice Add i Get i o refer o instan TreeMapNode prin intermediul atributului topNode; clasa TreeMapNode posed metodele publice Add i Find; orice instan TreeMapNode posed 2 referin e c tre alte instan e TreeMapNode, printr-un atribut de tip container, numit nodes;
5

orice instan TreeMapNode posed dou atribute key and value; atributul key este de un tip care implementeaz interfa a IComparable; atributul value este de un tip oarecare; Interpretarea acestei diagrame se realizeaz astfel: dreptunghiurile reprezint clase; sage ile reprezint rela ii ntre clase; n aceast diagrama toate rela iile sunt asocieri, prin care un obiect l refer pe altul; numele asocierii e numele atributului prin intermediul c ruia se realizeaz acea asociere; un num r asociat unei s ge i reprezint num rul de obiecte implicate n respectiva rela ie; dac num rul este supraunitar, de obicei este utilizat un tip de container; <<interface>> implic faptul c Icomparable este o interfa ;

B. Diagrame de obiecte O diagram de obiecte descrie un set de obiecte i rela iile dintre ele la un anumit moment n program (snapshot of memory).

Dreptunghiurile reprezint obiecte; numele clasei din care fac parte este subliniat. Rela iile dintre obiecte se numesc leg turi (links) i sunt derivate din asocierile dintre clase; leg turile sunt numite dup cele dou pozi ii din containerul nodes. C. Diagrame de secven O diagram de secven descrie implementarea unei metode; de exemplu:
6

Apelantul invoc metoda Add asupra unui obiect de tip TreeMap. Dac topNode este null, i se asociaz un obiect TreeMapNode, nou creat; altfel, se execut metoda Add asupra obiectului de tip TreeMapNode referit de topNode. Expresiile booleene se numesc garzi i au rolul de a selecta calea de execu ie. S ge ile mai mici, cu cercule e, se numesc atomi de date (data tokens) i reprezint argumentele recep ionate de o metod . Dreptunghiul pozi ionat vertical reprezint durata de execu ie a metodei Add. D. Diagrame de colaborare Dac o diagram de secven clarific colaborare clarific rela iile dintre obiecte: ordinea mesajelor, o diagram de

Leg turile dintre obiecte (link-uri) relev mesajele pe care i le transmit obiectele, n sensul dat de s ge ile mici. Mesajele sunt etichetate cu un nume, un num r de secven i g rzile care i se aplic .

Adapter Tip i scop: ablon structural; cum se compun clasele i obiectele pentru a forma structuri mai mari; permite reutilizarea codului surs vechi i incompatibil (legacy code); Solu ie: un intermediar (Adapter) permite unor clase cu interfe e incompatibile (Target i Adaptee) s lucreze mpreun ;

Participan i: Target: declararea interfe ei pe care clientul o va utiliza; Adaptee: declararea interfa ei ce trebuie adaptat (legacy code); Adapter: adapteaz interfa a Adaptee cu interfa a Target; Exemplu:
#include <iostream> using namespace std; class ITarget { public: virtual void executeRequest() = 0; virtual ~ITarget(){} }; // adapter class template <class TYPE> class Adapter: public ITarget { /* the old */ private: TYPE* object; // ptr-to-object attribute void (TYPE::* method)(); // ptr-to-member-function attribute public: Adapter( TYPE* object, void (TYPE::* method)() ) { this->object = object; this->method = method; } ~Adapter() { // the object will be created with new delete object; }

// the adapter "maps" the new to the old void executeRequest() { (object->*method)(); } };

// three old totally incompatible classes // no common base, no polymorphism class A { public: void doThis() { cout << "A::doThis()" << endl; } }; class B { public: void doThat() { cout << "B::doThat()" << endl; } }; class C { public: void doTheOther() { cout << "C::doTheOther()" << endl; } }; int main() { // one Adapter for each of those classes ITarget* adapters[3]; adapters[0] = new Adapter <A> ( new A(), &A::doThis ); adapters[1] = new Adapter <B> ( new B(), &B::doThat ); adapters[2] = new Adapter <C> ( new C(), &C::doTheOther );

for (int i = 0; i<3; ++i) { // "external polymorphism" adapters[i]->executeRequest(); } for (i = 0; i < 3; i++) { delete adapters[i]; } return 0; }

Observa ie: Exemplul anterior demonstreaz utilizarea pattern-ului pentru a induce polimorfismul din exterior, atunci cnd acesta nu exist .

Bridge Tip i scop: ablon structural; decupleaz un concept abstract de implementarea sa, a.. ambele s se poat modifica independent; Solu ie (idiomul handle-body): descrierea conceptului (handle) i implementarea sa (body) formeaz dou ierarhii ortogonale; un handle con ine un body; utilizatorul interactioneaz cu un handle, ins acesta redirectioneaz activitatea tre body;

Participan i: Abstraction: declararea interfe ei care descrie conceptul abstract; Implementor : declararea interfa ei care descrie implementarea conceptului abstract; RefinedAbstraction: extinde interfa a Abstraction; ConcreteImplementor: implementeaz interfa a Implementor; Observa ie: Un Adapter face sa func ioneze clase deja scrise; un Bridge face s func ioneze clase care vor fi scrise! Exemplu:
#include <vector> #include <algorithm> #include <string> #include <iostream> using namespace std; // implementation interface

class IPizzaImplementation { public: void printIngredients() { cout << "Ingredients: "; for_each( ingredients.begin(), ingredients.end(), printString); cout << endl; } protected: vector<string> ingredients; IPizzaImplementation() { ingredients.push_back("mozzarella"); ingredients.push_back("tomatoes"); } private: static void printString(string s) { cout << s << " "; } }; // concrete implementations class MarguerittaImplementation : public IPizzaImplementation { public: MarguerittaImplementation() { ingredients.push_back("basil"); ingredients.push_back("olive oil"); } }; class MarinaraImplementation : public IPizzaImplementation { public: MarinaraImplementation() { ingredients.push_back("olive oil"); ingredients.push_back("garlic"); ingredients.push_back("oregano"); } }; class CapricciosaImplementation : public IPizzaImplementation { public: CapricciosaImplementation() { ingredients.push_back("olive oil"); ingredients.push_back("mushrooms"); ingredients.push_back("artichokes"); ingredients.push_back("cooked ham"); } }; class QuattroFormaggiImplementation : public IPizzaImplementation { public: QuattroFormaggiImplementation() { ingredients.push_back("stracchino"); ingredients.push_back("fontina"); ingredients.push_back("gorgonzola"); } };

// abstraction class IPizza { public: virtual void printIngredients() = 0 { pBody->printIngredients();

} protected: IPizzaImplementation* pBody; }; // refined abstraction class IPizzaNapoletana : public Ipizza{}; class IPizzaLazio : public IPizza{};

class MarguerittaPizza: public IPizzaNapoletana { public: MarguerittaPizza() { pBody = new MarguerittaImplementation(); } /*virtual*/ void printIngredients() { cout << "Margueritta: "; IPizza::printIngredients(); } }; class MarinaraPizza: public IPizzaNapoletana { public: MarinaraPizza() { pBody = new MarinaraImplementation(); } /*virtual*/ void printIngredients() { cout << "Marinara: "; IPizza::printIngredients(); } }; class CapricciosaPizza: public IPizzaLazio { public: CapricciosaPizza() { pBody = new CapricciosaImplementation(); } /*virtual*/ void printIngredients() { cout << "Capricciosa: "; IPizza::printIngredients(); } }; class QuattroFormaggiPizza: public IPizzaLazio { public: QuattroFormaggiPizza() { pBody = new QuattroFormaggiImplementation(); } /*virtual*/ void printIngredients() { cout << "Quattro Formaggi: "; IPizza::printIngredients(); } }; int main() { IPizza* pizza[4]; pizza[0] = new MarinaraPizza; pizza[1] = new MarguerittaPizza; pizza[2] = new CapricciosaPizza;

pizza[3] = new QuattroFormaggiPizza;

for (int i = 0; i < 4; ++i) { pizza[i]->printIngredients(); } return 0; }

Composite Tip i scop: ablon structural; cum se compun clasele i obiectele pentru a forma structuri mai mari; construie te ierarhii arborescente de clase, de tip parte-ntreg; Solu ie: o clas abstract (Component) modeleaz simultan att obiectele primitive (Leaf), ct i obiectele compuse (Composite), ceea ce permite tratarea lor n mod uniform;

Participan i: Component: declararea interfe ei comune; Composite: define te comportamentul obiectelor compuse; Leaf: define te comportamentul obiectelor primitive; Exemplu:
#include <iostream> #include <vector> using namespace std; // create an common interface class IComponent { public: virtual void traverse() = 0; }; // leaf class Leaf: public IComponent { int value; public: Leaf(int val) : value(val){} void traverse() { cout << value << ' '; } };

// composite class Composite: public IComponent { vector<IComponent*> childrens; int value; public: Composite(int val) : value(val){} void add(IComponent* oneChildren) { childrens.push_back(oneChildren); } void traverse() { cout << value << " "; int nChildrens = childrens.size(); for (int i = 0; i < nChildrens ; i++) { childrens[i]->traverse(); } } }; class Row: public Composite { public: Row(int val): Composite(val){} void traverse() { cout << "Row"; Composite::traverse(); } }; class Column: public Composite { public: Column(int val): Composite(val){} void traverse() { cout << "Column"; Composite::traverse(); } }; int main() { Row firstRow(1); Column secondColumn(2); Column thirdColumn(3); Row fourthRow(4); Row fifthRow(5); firstRow.add( &secondColumn ); firstRow.add( &thirdColumn ); thirdColumn.add( &fourthRow ); thirdColumn.add( &fifthRow ); firstRow.add(&Leaf(6)); secondColumn.add(&Leaf(7)); thirdColumn.add(&Leaf(8)); fourthRow.add(&Leaf(9)); fifthRow.add(&Leaf(10)); firstRow.traverse(); cout << endl; return 0; } // Row1 // | // +-- Col2 // | | // | +-- 7 // | | // +-- Col3 // | | // | | // | +-- Row4 // | | | // | | | // | | +-- 9 // | | | // | +-- Row5 // | | | // | | | // | | +-- 10 // | +-- 8 // | | // +-- 6

Decorator Tip i scop: ablon structural; ata eaz , n mod dinamic, responsabilit i suplimentare unui obiect, independent de alte instan e ale aceleia i clase, ca alternativ la mo tenire (caracter static, se aplic ntregii clase); Solu ie: func ionalitatea original a unei clase Core este rafinat ntr-o interfa LCD (Lowest Common Denominator), din care se deriveaz att clasa Core, ct i clasa Wrapper; un Wrapper ncapsuleaz o referin c tre un obiect LCD, c ruia i deleag atribu iile;

Participan i: Interface: declararea interfe ei care descrie func ionalitatea Core; CoreFunc ionality: implementarea conceptului Core; OptionalWrapper : descrierea conceptului de decorator OptinalOne, OptionalTwo, OptionalThree: diverse tipuri de decorator; Exemplu:
#include <vector> #include <algorithm> #include <string> #include <iostream> using namespace std; // interface LCD class IPizzaNapoletana { public: virtual void printIngredients() = 0;

virtual ~IPizzaNapoletana(){} }; // class Margueritta (Core) is a IPizzaNapoletana (LCD) class Margueritta : public IPizzaNapoletana { public: Margueritta() { ingredients.push_back("mozzarella"); ingredients.push_back("tomatoes"); ingredients.push_back("basil"); ingredients.push_back("olive oil"); } void printIngredients() { cout << "Margueritta ingredients: "; for_each( ingredients.begin(), ingredients.end(), printString); cout << endl; } protected: vector<string> ingredients; private: static void printString(string s) { cout << s << " "; } }; // class Decorator (is a IPizzaNapoletana ) class Decorator: public IPizzaNapoletana { IPizzaNapoletana* pInnerObject; public: Decorator(IPizzaNapoletana* p) : pInnerObject(p){} // delegate to base class /*virtual*/ void printIngredients() { pInnerObject->printIngredients(); } }; class KetchupDecorator : public Decorator { public: KetchupDecorator(IPizzaNapoletana* p): Decorator(p){} /*virtual*/ void printIngredients() { // delegate to base class and add extra stuff Decorator::printIngredients(); cout << "Ketchup" << endl; } }; class PepperDecorator : public Decorator { public: PepperDecorator(IPizzaNapoletana* p): Decorator(p){} /*virtual*/ void printIngredients() { // delegate to base class and add extra stuff Decorator::printIngredients(); cout << "Pepper" << endl; } }; int main() { // client has the responsibility to compose desired configurations IPizzaNapoletana* pPizza = new PepperDecorator( new KetchupDecorator( new Margueritta ) ); pPizza->printIngredients(); return 0; }

You might also like