Sunteți pe pagina 1din 44

Chain of Responsibility

Tip i scop:
ablon comportamental;
evit dependena unui emitor de un anumit receptor cu ajutorul unei colecii de
receptori (ce ar putea fiecare gestiona o cerere);
Soluie:
se construiete un lan (pipeline) de noduri ce pot gestiona o cerere;
emitorul 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>
usingnamespacestd;
classBase
{
Base* nextLink;
public:
Base() : nextLink(NULL) {}
voidsetNext(Base* link){nextLink =link; }
voidaddLink(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 voidhandleRequest(const string&request)
{
nextLink->handleRequest(request);
}
};
classHandler1: publicBase
{
public:
/*virtual*/ voidhandleRequest( 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";
}
}
};
classHandler2: publicBase
{
public:
/*virtual*/ voidhandleRequest(const string&request)
{
if ( rand() % 3 )
{
cout <<"Handler2 passsed ...";
Base::handleRequest(request);
}
else
{
cout <<"Handler2 handled " <<request <<"\n";
}
}
};
classHandler3: publicBase
{
public:
/*virtual*/ voidhandleRequest(const string&request)
{
if ( rand() % 3 )
{
cout <<"Handler3 passsed ...";
Base::handleRequest(request);
}
else
{
cout <<"Handler3 handled " <<request <<"\n";
}
}
};
int main()
{
srand(time(0));
Handler1root;
Handler2two;
root.addLink(&two);
Handler3thr;
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;
definete o dependen de tipone-to-many ntre obiecte, a.. atunci cnd un obiect
i schimb starea, obiectele dependente sunt notificate automat despre acest fapt;
Soluie:
un obiect Subject gestioneaz o colecie de obiecteObserver;
atunci cnd sunt create, obiectele Observer trebuie s se nregistreze la obiectul
Subject; acesta include noul obiect Observer n colecia sa;
atunci cnd obiectul Subject i schimb starea, el informeaz n mod automat
toate obiecteleObserver aflate n colecia sa;
Participani:
Subject: interfa pentru nregistrarea observatorilor i notificarea lor automat atunci
cnd se schimb starea;
Observer: declararea interfeei unui observator (metoda virtual notify() );
ConcreteObserverA, ConcreteObserverB: implementarea interfeei de observator
(modul specific n care acesta reacioneaz anunci cnd subiectul i schimb starea);
Exemplu:
#include<iostream>
#include<vector>
usingnamespacestd;
// observer interface
classIAlarmListener
{
public:
virtual voidalarm() =0; // modul in care trebuie sa reactioneze dispozitivul la declansarea alarmei
};
// subject
classSensorSystem
{
vector <IAlarmListener* >listeners; // colectia de dispozitive
public:
voidattach( IAlarmListener* al)
{
listeners.push_back(al);
}
// notify all
voidsoundTheAlarm()
{
cout <<"ALARM!" <<endl;
int nSize =listeners.size();
for (int i =0; i <nSize; ++i)
listeners[i]->alarm();
}
};
// specific observer
classLighting: publicIAlarmListener
{
public:
/*virtual*/ voidalarm()
{
cout <<"Lights up!" <<endl;
}
};
// another specific observer
classGates: publicIAlarmListener
{
public:
/*virtual*/ voidalarm()
{
cout <<"Gates close!" <<endl;
}
};
int main()
{
SensorSystemss;
ss.attach( &Gates() );
ss.attach( &Lighting() );
ss.soundTheAlarm();
return 0;
}
Strategy
Tip i scop:
ablon comportamental;
definete o familie de algoritmi ce pot fi utilizai unul n locul celuilat;
Soluie:
un algoritm este ncapsulat ntr-o ierarhie de clase;
clienii dein doar o referin ctre clasa de baz;
variata aleas depinde de factori (context) cunoscui doar la execuie (run-time);
Exemplu:
#include<iostream>
#include<fstream>
#include<string>
usingnamespacestd;
enum{nWordWidth =50, nLineWidth =200 };
enum{Left=1, Right, Center };
classIStrategy
{
public:
IStrategy(int width): _width(width){}
voidformat()
{
ifstreaminFile("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 voidjustify(char* line) =0;
};
classLeftStrategy: publicIStrategy
{
public:
LeftStrategy(int width): IStrategy(width){}
private:
/* virtual */ voidjustify(char* line)
{
// show the line
cout <<line <<endl;
// make clean
line[0] ='\0';
}
};
classRightStrategy: publicIStrategy
{
public:
RightStrategy(int width): IStrategy(width){}
private:
/* virtual */ voidjustify(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';
}
};
classCenterStrategy: publicIStrategy
{
public:
CenterStrategy(int width): IStrategy(width){}
private:
/* virtual */ voidjustify(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';
}
};
classTest
{
public:
Test () : _strategy(NULL) {}
voidsetStrategy(int type, int width);
voiddoIt() {_strategy->format(); }
private:
IStrategy* _strategy;
};
voidTest::setStrategy(int type, int width)
{
delete_strategy;
switch (type)
{
default :
caseLeft : _strategy =newLeftStrategy(width); break;
caseRight : _strategy =newRightStrategy(width);break;
caseCenter : _strategy =newCenterStrategy(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;
definete paii unui algoritm, lsnd clasele client sa rafineze aceti pai;
Soluie:
proiectantul decide care pai sunt invariani (standard) i care sunt variabili
(personalizabili);
paii invariani sunt implementai n clasele de baz;
paii variabili nu sunt implementai sau li se ofer o implementare implicit;
Exemplu:
#include<iostream>
usingnamespacestd;
classBase
{
// Invariant steps
voida() { cout <<"a "; }
voidc() { cout <<"c "; }
voide() { cout <<"e "; }
// Steps requiring peculiar implementations are "placeholders" in base class
virtual voidph1() =0;
virtual voidph2() =0;
public:
// Standardize the skeleton of an algorithm in a base class "template method"
voidexecute()
{
a();
ph1();
c();
ph2();
e();
}
};
// Derived classes implement placeholder methods
classOne: publicBase
{
/*virtual*/voidph1() {cout <<"b "; }
/*virtual*/voidph2() {cout <<"d "; }
};
classTwo: publicBase
{
/*virtual*/voidph1() {cout <<"2 "; }
/*virtual*/voidph2() {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 operaii pe o structur, f a modifica (polua) clasele
componente i f a interoga tipul obiectului din structur;
Soluie:
operaia 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 ctre un obiect Element;
ierarhia Element definete o metod virtual Accept(), metod ce posed un
argument de tip referin ctreVisitor;
Exemplu:
#include<iostream>
#include<string>
usingnamespacestd;
classIVisitor;
// add an "accept" method to the "element" hierarchy
classIElement
{
public:
virtual voidAccept( IVisitor& visitor) =0;
};
classThis: publicIElement
{
public:
/*virtual*/ voidAccept( IVisitor& visitor );
stringthiss() {return "This"; }
};
classThat: publicIElement
{
public:
/*virtual*/voidAccept( IVisitor& visitor );
stringthat() {return "That"; }
};
classTheOther: publicIElement
{
public:
/*virtual*/voidAccept( IVisitor& visitor );
stringtheOther() {return "TheOther"; }
};
// create a "visitor" base class with a "visit" method for every "element" type
classIVisitor
{
public:
virtual voidVisit(This* element) =0;
virtual voidVisit(That* element) =0;
virtual voidVisit(TheOther* element) =0;
};
/*virtual*/ voidThis::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
/*virtual*/ voidThat::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
/*virtual*/ voidTheOther::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
// create a "visitor" derived class for each "operation" to do on "elements"
classUpVisitor: publicIVisitor
{
/*virtual*/ voidVisit(This* element)
{
cout <<"do Up on " +element->thiss() <<'\n';
}
/*virtual*/ voidVisit(That* element)
{
cout <<"do Up on " +element->that() <<'\n';
}
/*virtual*/ voidVisit(TheOther* element)
{
cout <<"do Up on " +element->theOther() <<'\n';
}
};
classDownVisitor: publicIVisitor
{
/*virtual*/ voidVisit(This* element)
{
cout <<"do Down on " +element->thiss() <<'\n';
}
/*virtual*/ voidVisit(That* element)
{
cout <<"do Down on " +element->that() <<'\n';
}
/*virtual*/ voidVisit(TheOther* element)
{
cout <<"do Down on " +element->theOther() <<'\n';
}
};
int main()
{
// make the structure
IElement* list[] ={newThis(), newThat(), newTheOther() };
// "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 creaional;
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-unobject pool;
o obiectul poate fi configurat n diverse moduri;
duplicarea codului surs;
informaii 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).
Soluie:
cte un Factory responsabil pentru crearea unui tip de obiect (produs);
unAbstract Factory incapsuleaz un grup deFactory ce au o tem comun;
Participani:
AbstractFactory: declararea interfeei pentru operaiile de creare de obiecte;
ConcreteFactory1:
ConcreteFactory2: implementarea operaiilor pentru crearea de obiecte;
AbstractProductA
AbstractProductB: interfeele obiectelor ce vor fi create;
ProductA1
ProductB1: obiectele create de ctre fabrica concret ConcreteFactory1;
ProductA2
ProductB2: obiectele create de ctre fabrica concret ConcreteFactory2;
Exemplu:
#include<iostream>
usingnamespacestd;
// AbstractProductA
struct ICarTrip
{
};
classBusinessCarTrip : publicICarTrip
{
public:
BusinessCarTrip()
{
cout <<"Luxury travel with a car" <<endl;
}
};
classEconomicCarTrip : publicICarTrip
{
public:
EconomicCarTrip()
{
cout <<"Economic travel with a car" <<endl;
}
};
// AbstractProductB
struct IAirplaneTrip
{
};
classBusinessAirplaneTrip : publicIAirplaneTrip
{
public:
BusinessAirplaneTrip()
{
cout <<"Luxury travel with an airplane" <<endl;
}
};
classEconomicAirplaneTrip : publicIAirplaneTrip
{
public:
EconomicAirplaneTrip()
{
cout <<"Economic travel with an airplane" <<endl;
}
};
// AbstractFactory
classITripFactory
{
public:
virtual ICarTrip* makeCarTrip() =0;
virtual IAirplaneTrip* makeAirplaneTrip() =0;
};
// ConcreteFactory1
classBussinesTripFactory : publicITripFactory
{
public:
ICarTrip* makeCarTrip()
{
returnnewBusinessCarTrip;
}
IAirplaneTrip* makeAirplaneTrip()
{
returnnewBusinessAirplaneTrip;
}
};
// ConcreteFactory2
classEconomicTripFactory : publicITripFactory
{
public:
ICarTrip* makeCarTrip()
{
returnnewEconomicCarTrip;
}
IAirplaneTrip* makeAirplaneTrip()
{
returnnewEconomicAirplaneTrip;
}
};
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 =newEconomicTripFactory;
}
else
{
tripFactory =newBussinesTripFactory;
}
carTrip =tripFactory->makeCarTrip();
airplaneTrip =tripFactory->makeAirplaneTrip();
return 0;
}
Observaii:
Deoarece produsele sunt precizate n interfaa de AbstractFactory, adugarea
de noi produse este dificil, presupunnd modificarea tuturor versiunilor de
ConcreteFactory;
Schimbarea tipului deConcreteFactory (n punctul de instaniere), conduce la
schimbarea unei ntregi familii de produse.
Builder
Tip i scop:
ablon creaional;
abstractizeaz paii n construcia unui obiect, a.. diferite implementri ale acestor
pai 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-unobject pool;
o obiectul poate fi configurat n diverse moduri;
duplicarea codului surs;
informaii 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).
Soluie:
un Builder este responsabil pentru crearea unui versiuni de obiect (produs), i
spunde la comenzile unui Director;
unDirector manageriaz unBuilder;
clientul instaniaz un Director i i asociaz un Builder corespunztor cerinelor
sale;
Participani:
Builder: declararea interfeei pentru paii implicai n crearea unui obiect;
ConcreteBuilder: implementarea pailor implicai n crearea unui obiect;
Director: construiete un obiect prin intermediul unui ConcreteBuilder;
Product: obiectul final, construit la solicitarea unui Director, de ctre un
ConcreteBuilder;
Exemplu:
#include<vector>
#include<algorithm>
#include<string>
#include<iostream>
usingnamespacestd;
// Product
classPizzaNapoletana
{
staticvoidprintString(strings)
{
cout <<s <<" ";
}
protected:
vector<string>ingredients;
stringname;
public:
voidprintIngredients()
{
cout <<name <<endl;
cout <<"Ingredients: ";
for_each( ingredients.begin(), ingredients.end(), printString);
cout <<endl;
}
voidsetName( const string& name )
{
this->name =name;
}
voidaddCheese(const string& cheese)
{
ingredients.push_back( cheese );
}
voidaddTomatoes( const string& tomatoes )
{
ingredients.push_back(tomatoes);
}
voidaddOil( const string& oil )
{
ingredients.push_back(oil);
}
voidaddBasil()
{
ingredients.push_back("basil");
}
voidaddGarlic()
{
ingredients.push_back("garlic");
}
voidaddOregano()
{
ingredients.push_back("oregano");
}
voidaddOlives()
{
ingredients.push_back("olives");
}
};
// Builder
classIPizzaNapoletanaRecipe
{
protected:
PizzaNapoletana* pizza;
public:
PizzaNapoletana* getPizza()
{
returnpizza;
}
// abstract steps to make pizza
virtual voidcreateNewPizza() =0;
virtual voidputCheese() =0;
virtual voidputTomatoes() =0;
virtual voidputOil() =0;
virtual voidputBasil() =0;
virtual voidputGarlic() =0;
virtual voidputOregano() =0;
virtual voidputOlives() =0;
};
// ConcreteBuilder
classMarguerittaRecipe : publicIPizzaNapoletanaRecipe
{
public:
voidcreateNewPizza()
{
pizza =newPizzaNapoletana;
pizza->setName("Margueritta");
}
voidputCheese()
{
pizza->addCheese("sliced mozzarella");
}
voidputTomatoes()
{
pizza->addTomatoes("San Marzano tomatoes");
}
voidputOil()
{
pizza->addOil("olive oil");
}
voidputBasil()
{
pizza->addBasil();
}
voidputGarlic()
{
return;
}
voidputOregano()
{
return;
}
voidputOlives()
{
return;
}
};
// ConcreteBuilder
classMarinaraRecipe : publicIPizzaNapoletanaRecipe
{
public:
voidcreateNewPizza()
{
pizza =newPizzaNapoletana;
pizza->setName("Marinara");
}
voidputCheese()
{
pizza->addCheese("mozzarella");
}
voidputTomatoes()
{
pizza->addTomatoes("tomatoes");
}
voidputOil()
{
pizza->addOil("olive oil");
}
voidputBasil()
{
return;
}
voidputGarlic()
{
pizza->addGarlic();
}
voidputOregano()
{
pizza->addOregano();
}
voidputOlives()
{
pizza->addOlives();
}
};
// Director
classChef
{
IPizzaNapoletanaRecipe* pizzaRecipe;
public:
Chef()
{
pizzaRecipe =NULL;
}
voidsetPizzaRecipe(IPizzaNapoletanaRecipe* pizzaRecipe)
{
this->pizzaRecipe =pizzaRecipe;
}
PizzaNapoletana* cookPizza()
{
if ( NULL ==pizzaRecipe )
{
cout <<"No recipe associated! " <<endl;
returnNULL;
}
// manage the steps to cook pizza
pizzaRecipe->createNewPizza();
pizzaRecipe->putCheese();
pizzaRecipe->putTomatoes();
pizzaRecipe->putOil();
pizzaRecipe->putBasil();
pizzaRecipe->putGarlic();
pizzaRecipe->putOregano();
pizzaRecipe->putOlives();
returnpizzaRecipe->getPizza();
}
};
int main()
{
// director
Chef someChef;
// try make pizza
PizzaNapoletana* pizza0 =someChef.cookPizza();
if ( NULL !=pizza0 )
{
pizza0->printIngredients();
}
// set new builder
MarguerittaRecipepizzaRecipe1;
someChef.setPizzaRecipe( &pizzaRecipe1 );
// make pizza
PizzaNapoletana* pizza1 =someChef.cookPizza();
pizza1->printIngredients();
// set new builder
MarinaraRecipepizzaRecipe2;
someChef.setPizzaRecipe( &pizzaRecipe2 );
// make pizza
PizzaNapoletana* pizza2 =someChef.cookPizza();
pizza2->printIngredients();
return 0;
}
Factory Method
Tip i scop:
ablon creaional;
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-unobject pool;
o obiectul poate fi configurat n diverse moduri;
duplicarea codului surs;
informaii 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).
Soluie:
cte ometod 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 aceeai interfa;
metoda Factory poate fi suprancrcat n clasele derivate, pentru a crea o anumit
versiune a respectivului produs.
Participani:
Product: definete interfaa obiectului ce va fi creat;
ConcreteProduct1:
ConcreteProduct2: diverse versiuni (concretizri) ale obiectului ce va fi creat;
Creator: definete o metod ce returneaz un obiect de tipul Product;
ConcreteCreator1:
ConcreteCreator2: suprascrie metoda pentru a returna versiunea dorit a
obiectului Product.
Exemplu:
#include<vector>
#include<map>
#include<algorithm>
#include<string>
#include<iostream>
usingnamespacestd;
// Product
classIPizzaNapoletana
{
public:
virtual stringname() =0;
voidprintIngredients()
{
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:
staticvoidprintString(strings)
{
cout <<s <<" ";
}
};
enum{MarguerittaID, MarinaraID, UnknownPizzaID };
// ConcreteProduct1
classMargueritta : publicIPizzaNapoletana
{
public:
Margueritta()
{
ingredients.push_back("basil");
ingredients.push_back("olive oil");
}
stringname() {returnstring("Margueritta"); }
};
// ConcreteProduct2
classMarinara : publicIPizzaNapoletana
{
public:
Marinara()
{
ingredients.push_back("olive oil");
ingredients.push_back("garlic");
ingredients.push_back("oregano");
}
stringname() {returnstring("Marinara"); }
};
// auxiliary classes
classIOwen
{
public:
virtual voidbaking( IPizzaNapoletana*& ) =0;
};
classWoodBrickOven : publicIOwen
{
public:
voidbaking( IPizzaNapoletana*& pizza )
{
cout <<"Pizza " <<pizza->name() <<" was baked in a wood brick oven" <<endl;
}
};
classElectricDeckOven : publicIOwen
{
public:
voidbaking( IPizzaNapoletana*& pizza )
{
cout <<"Pizza " <<pizza->name() <<" was baked in an electric deck oven" <<endl;
}
};
// Creator
classIRestaurant
{
protected:
// specific owen
IOwen* pOwen;
public:
// factory method (default implementation)
virtual IPizzaNapoletana* makePizza( int pizzaId ) =0
{
IPizzaNapoletana* tmpPizza =NULL;
switch ( pizzaId )
{
caseMarguerittaID : tmpPizza =newMargueritta; break;
caseMarinaraID : tmpPizza =newMarinara; break;
}
if ( NULL ==tmpPizza )
{
cout <<"Unknown pizza ID!" <<endl;
}
else
{
cout <<"Name: " <<tmpPizza->name() <<endl;
tmpPizza->printIngredients();
}
returntmpPizza;
}
};
// ConcreteCreator1
classDomneasca : publicIRestaurant
{
map<int, int>pizzaPrice;
public:
Domneasca()
{
pOwen =newWoodBrickOven;
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;
}
returntmpPizza;
}
};
// ConcreteCreator2
classHot : publicIRestaurant
{
vector<int>pizzaPrice;
public:
Hot()
{
pOwen =newElectricDeckOven;
// 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;
}
returntmpPizza;
}
};
int main()
{
Domneascarestaurant1;
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 creaional;
evit crearea de noi obiecte prin intermediul operatorului new atunci cnd acest
lucru este prohibitiv;
Prototype: instan responsabil pentru crearea celorlalte obiecte prin clonare.
Participani:
Prototype: declararea interfeei pentru clonare;
ConcretePrototype: implementarea operaiei de clonare;
Client: construiete un nou obiect cerndu-I prototipului s se cloneze;
Exemplu:
#include<vector>
#include<string>
#include<iostream>
usingnamespacestd;
enumpizzaID {MarguerittaID, MarinaraID, UnknownPizzaID };
// Product
classIPizzaNapoletana
{
public:
voidprintName()
{
cout <<pizzaName <<endl;
}
// client calls this public static member function when it needs an instance of an IPizzaNapoletana subclass
staticIPizzaNapoletana* Clone( pizzaIDid)
{
int nPizzaTypes =prototypeCollection.size();
for (int i =0; i <nPizzaTypes; ++i)
{
if ( prototypeCollection[i]->returnID() ==id)
{
returnprototypeCollection[i]->makeSpecificClone();
}
}
returnNULL;
}
private:
staticvector<IPizzaNapoletana*>prototypeCollection; // addPrototype() saves each prototype object here
protected:
// each subclass of IPizzaNapoletana registers its prototype
staticvoidaddPrototype(IPizzaNapoletana* pizza)
{
prototypeCollection.push_back( pizza );
}
virtual pizzaIDreturnID() =0;
virtual IPizzaNapoletana* makeSpecificClone() =0;
stringpizzaName;
};
vector<IPizzaNapoletana*>IPizzaNapoletana::prototypeCollection;
// ConcreteProduct1
classMargueritta : publicIPizzaNapoletana
{
private:
// this is subclass's prototype object
// default ctor will be called, which registers it
staticMargueritta_objectMargueritta;
// this is only called when the private static data member is inited
Margueritta()
{
pizzaName="Margueritta";
addPrototype(this);
}
protected:
/*virtual*/ pizzaIDreturnID()
{
returnMarguerittaID;
}
/*virtual*/ IPizzaNapoletana* makeSpecificClone()
{
// call copy constructor
returnnewMargueritta( _objectMargueritta );
}
};
// ConcreteProduct2
classMarinara : publicIPizzaNapoletana
{
private:
// this is subclass's prototype object
// default ctor will be called, which registers it
staticMarinara_objectMarinara;
// this is only called when the private static data member is inited
Marinara()
{
pizzaName="Marinara";
addPrototype(this);
}
protected:
/*virtual*/ pizzaIDreturnID()
{
returnMarinaraID;
}
/*virtual*/ IPizzaNapoletana* makeSpecificClone()
{
returnnewMarinara( _objectMarinara );
}
};
// register the prototypes
MarguerittaMargueritta::_objectMargueritta;
MarinaraMarinara::_objectMarinara;
int main()
{
const int HOW_MANY__PIZZA =5;
pizzaIDinput[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)
deletepizza[i];
return 0;
}
Unified Modeling Language (UML)
UML este o notaie grafic utilizat pentru a descrie/modela concepte din
software, pe trei nivele posibile:
conceptual diagrame aflate n strns relaie cu limbajul natural, utilizate pentru
a descrie (concepte i abstracii) o preoblem la nivel uman; deoarece nu sunt
supuse unor reguli semantice, nelesul lor poate fi ambiguu i interpretabil;
specificaie diagrame ce descriu o propunere de proiectare a software-ului (o
soluie 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 modelm? Modelele sunt construite pentru a afla dac entitatea
modelat (un avion, un pod, o cldire, etc) va funciona! Aceasta nsemn c modelul
trebuie s fie testabil. Nu exist ns criterii pentru a evalua diagramele UML
(evaluare subiectiv).
considerm, de exemplu, afirmaia: A dog is ananimal.
La nivel conceptual, diagrama descrie dou dou entiti
(Animal i Dog), conectate printr-o relaie de generalizare. Un
Animal este o generalizare pentru unDog. UnDog este un caz
special de Animal. Nimic altceva nu se mai poate deduce din
aceast diagram.
La nivel de specificaie sau de implementare, acest
diagram are ns un neles mai precis:
class Animal {};
class Dog : public Animal {};
Codul surs definete clasele Animal i Dog ca fiind
interconectate printr-o relaie de motenire; astfel, modelul descrie o parte din
program.
n UML exist 3 tipuri generale de diagrame:
statice descriu structura logic (clase, obiecte i relaiile dintre ele) care nu se
modific;
dinamice descriu felul n care entitile software se modific n timpul execuiei;
fizice descriu structura fizic nemodificabil a entitilor software (fiiere surs,
fiiere binare, biblioteci, fiiere de date) i relaiile dintre acestea.
2
Considerm urmtorul program drept exemplu:
/ / const ai nt s. h
/ / Thi s i s a "const r ai nt s" base cl ass
/ / We need t o pl ace a r equi r ement on a t empl at e par amet er
/ / t o ensur e some f aci l i t y wi l l exi st !
/ / For exampl e: D must be der i ved f r omB
t empl at e <t ypename D, t ypename B> cl ass I sDer i vedFr om
{
/ / pr i vat e st at i c met hod, t o be cal l ed onl y f r omdef aul t const r uct or
st at i c voi d Const r ai nt s( D* pDer i ved)
{
B* pBase = pDer i ved; / / i f t hi s conver si on wor ks,
/ / t hen D I sDer i vedFr omB
pBase = pDer i ved; / / suppr ess war ni ngs about unused var i abl es. . .
}
/ / no one can i nst ant i at e t hi s cl ass di r ect l y
pr ot ect ed:
/ / c- t or
I sDer i vedFr om( )
{
/ / p i s poi nt er t o f unct i on who r ecei ves D* and r et ur ns voi d
/ / p i s ni t i al i zed, but never cal l ed!
voi d ( *p) ( D*) = Const r ai nt s;
}
};
/ / t ampl at e speci al i zat i on
/ / f or ce i t t o f ai l i n t he case wher e B i s voi d
t empl at e<t ypename D> cl ass I sDer i vedFr om<D, voi d>
{
I sDer i vedFr om( )
{
char * p = ( i nt *) 0; / * er r or */
}
};
#i ncl ude "const r ai nt s. h"
#i ncl ude <st r i ng>
#i ncl ude <i ost r eam>
usi ng namespace st d;
t empl at e <t ypename T> cl ass I Compar abl e
{
publ i c:
/ / r et ur n val ue:
/ / negat i ve: cur r ent i nst ance pr ecedes t he ( *pObj ect ) obj ect i n t he sor t or der
/ / zer o: cur r ent i nst ance occur s i n t he same posi t i on i n t he sor t or der as t he
/ / ( *pObj ect ) obj ect
/ / posi t i ve: cur r ent i nst ance f ol l ows t he ( *pObj ect ) obj ect i n t he sor t or der
vi r t ual i nt Compar eTo( const T& obj ect ) = 0;
};
/ / a "compar abl e" st r i ng
cl ass Compar abl eSt r i ng : publ i c st r i ng, publ i c I Compar abl e<Compar abl eSt r i ng>
{
publ i c:
Compar abl eSt r i ng( char * si r ) : st r i ng( si r ) {}
Compar abl eSt r i ng( st r i ng si r ) : st r i ng( si r ) {}
3
/ *vi r t ual */ i nt Compar eTo( const Compar abl eSt r i ng& obj ect )
{
/ / st r i ng al r eady i mpl ement s a "compar e" met hod;
/ / so, we wi l l use i t !
r et ur n ( st at i c_cast <st r i ng*>( t hi s) ) - >compar e( obj ect ) ;
}
};
t empl at e <t ypename K, t ypename T > cl ass Tr eeMap :
/ *must ensur e*/ I sDer i vedFr om<K, I Compar abl e<K> >
{
/ / i nner cl ass; i mpl ement at i on det ai l
cl ass Tr eeMapNode
{
pr i vat e:
enumDi r ect i on {LESS = 0, GREATER};
/ / cur r ent node
K key;
T val ue;
/ / t wo sons
Tr eeMapNode* nodes[ 2] ;
voi d AddSubNode( Di r ect i on d, const K& key, const T& val ue)
{
i f ( NULL == nodes[ d] )
{
/ / make new son node
nodes[ d] = new Tr eeMapNode( key, val ue) ;
}
el se
{
/ / updat e son node
nodes[ d] - >Add( key, val ue) ;
}
}
T* Fi ndSubNodeFor Key( Di r ect i on d, const K& key)
{
r et ur n nodes[ d] == NULL ? NULL : nodes[ d] - >Fi nd( key) ;
}
publ i c:
Tr eeMapNode( const K& someKey, const T& someVal ue)
: key( someKey) , val ue( someVal ue)
{
nodes[ Di r ect i on: : LESS ] = NULL;
nodes[ Di r ect i on: : GREATER] = NULL;
}
~Tr eeMapNode( )
{
del et e nodes[ Di r ect i on: : LESS ] ;
del et e nodes[ Di r ect i on: : GREATER] ;
}
Di r ect i on Sel ect SubNode( const K& key)
{
r et ur n ( ( t hi s- >key) . Compar eTo( key) < 0) ? GREATER: LESS;
}
T* Fi nd( const K& key)
{
4
i f ( ( t hi s- >key) . Compar eTo( key) == 0)
r et ur n new T( val ue) ;
/ / mor e deep seeki ng
r et ur n Fi ndSubNodeFor Key( Sel ect SubNode( key) , key) ;
}
voi d Add( const K& key, const T& val ue)
{
i f ( ( t hi s- >key) . Compar eTo( key) == 0)
{
/ / set new val ue
t hi s- >val ue = val ue;
}
el se
{
/ / deep addi ng
AddSubNode( Sel ect SubNode( key) , key, val ue) ;
}
}
};
/ / r oot node
Tr eeMapNode* t opNode; / / st ar t i ng poi nt
publ i c:
Tr eeMap( ) : t opNode( NULL) {}
voi d Add( const K& key, const T& val ue)
{
/ / empt y t r ee ?
i f ( NULL == t opNode)
{
t opNode = new Tr eeMapNode( key, val ue) ;
}
el se
{
t opNode- >Add( key, val ue) ;
}
}
T* Get ( const K& key)
{
r et ur n ( NULL == t opNode) ? NULL : t opNode- >Fi nd( key) ;
}
~Tr eeMap( )
{
del et e t opNode;
}
};
i nt mai n( )
{
t ypedef Tr eeMap<Compar abl eSt r i ng, st r i ng> di ct i onar ;
di ct i onar d;
d. Add( Compar abl eSt r i ng( "oop") , st r i ng( "met hod of devel opi ng sof t war e t hat
model s t he r eal wor l d usi ng obj ect s") ) ;
d. Add( Compar abl eSt r i ng( "obj ect ") , st r i ng( "sel f cont ai ned i t emof dat a
t hat can onl y be accessed or changed i n a cont r ol l ed way") ) ;
5
d. Add( Compar abl eSt r i ng( "pol ymor phi sm") , st r i ng( "many shapes") ) ;
d. Add( Compar abl eSt r i ng( "vi r t ual ") , st r i ng( "can be over r i dden i n a der i ved
cl ass") ) ;
d. Add( Compar abl eSt r i ng( "over r i dden") , st r i ng( "di f f er ent behavi our ") ) ;
cout << "Quest i on == ";
st r i ng quest i on;
ci n >> quest i on;
st r i ng* answer = d. Get ( Compar abl eSt r i ng( quest i on) ) ;
i f ( NULL ! = answer )
{
cout << quest i on << " == " << *answer << endl ;
}
el se
{
cout << "I have no i deea what i s " << quest i on << "! " << endl ;
}
del et e answer ;
r et ur n 0;
}
A. Diagrame de clase
O diagram de clase descrie cele mai importante clase dintr-un program,
precum i relaiile dintre acestea.
Astfel:
clasa TreeMap posed metodele publice Add i Get i o refer o instan
TreeMapNode prin intermediul atributului topNode;
clasaTreeMapNode posed metodele publiceAdd i Find;
orice instan TreeMapNode posed 2 referine ctre alte instaneTreeMapNode,
printr-un atribut de tip container, numit nodes;
6
orice instan TreeMapNode posed dou atributekey andvalue; atributul key este
de un tip care implementeaz interfaaIComparable; atributul value este de un tip
oarecare;
Interpretarea acestei diagrame se realizeaz astfel:
dreptunghiurile reprezint clase;
sageile reprezint relaii ntre clase; n aceast diagrama toate relaiile sunt
asocieri, prin care un obiect l refer pe altul; numele asocierii e numele
atributului prin intermediul cruia se realizeaz acea asociere;
un numr asociat unei sgei reprezint numrul de obiecte implicate n respectiva
relaie; dac numrul 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 relaiile dintre ele la un
anumit moment n program (snapshot of memory).
Dreptunghiurile reprezint obiecte; numele clasei din care fac parte este
subliniat. Relaiile dintre obiecte se numesc legturi (links) i sunt derivate din
asocierile dintre clase; legturile sunt numite dup cele dou poziii din containerul
nodes.
C. Diagrame de secven
Odiagram de secven descrie implementarea unei metode; de exemplu:
7
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 execuie. Sgeile mai mici,
cu cerculee, se numesc atomi de date (data tokens) i reprezint argumentele
recepionate de o metod. Dreptunghiul poziionat vertical reprezint durata de
execuie a metodei Add.
D. Diagrame de colaborare
Dac o diagram de secven clarific ordinea mesajelor, o diagram de
colaborare clarific relaiile dintre obiecte:
Legturile dintre obiecte (link-uri) relev mesajele pe care i le transmit
obiectele, n sensul dat de sgeile mici. Mesajele sunt etichetate cu un nume, un
numr de secven i grzile 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);
Soluie:
un intermediar (Adapter) permite unor clase cu interfee incompatibile (Target i
Adaptee) s lucreze mpreun;
Participani:
Target: declararea interfeei pe care clientul o va utiliza;
Adaptee: declararea interfaei ce trebuie adaptat (legacy code);
Adapter: adapteaz interfaaAdaptee cu interfaaTarget;
Exemplu:
#include<iostream>
usingnamespacestd;
classITarget
{
public:
virtual voidexecuteRequest() =0;
virtual ~ITarget(){}
};
// adapter class
template <classTYPE>classAdapter: publicITarget
{
/* 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
deleteobject;
}
// the adapter "maps" the new to the old
voidexecuteRequest()
{
(object->*method)();
}
};
// three old totally incompatible classes
// no common base, no polymorphism
classA
{
public:
voiddoThis()
{
cout <<"A::doThis()" <<endl;
}
};
classB
{
public:
voiddoThat()
{
cout <<"B::doThat()" <<endl;
}
};
classC
{
public:
voiddoTheOther()
{
cout <<"C::doTheOther()" <<endl;
}
};
int main()
{
// one Adapter for each of those classes
ITarget* adapters[3];
adapters[0] =newAdapter <A>( newA(), &A::doThis );
adapters[1] =newAdapter <B>( newB(), &B::doThat );
adapters[2] =newAdapter <C>( newC(), &C::doTheOther );
for (int i =0; i<3; ++i)
{
// "external polymorphism"
adapters[i]->executeRequest();
}
for (i =0; i <3; i++)
{
deleteadapters[i];
}
return 0;
}
Observaie: 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;
Soluie (idiomul handle-body):
descrierea conceptului (handle) i implementarea sa (body) formeaz dou ierarhii
ortogonale;
unhandle conine unbody;
utilizatorul interactioneaz cu un handle, ins acesta redirectioneaz activitatea
trebody;
Participani:
Abstraction: declararea interfeei care descrie conceptul abstract;
Implementor: declararea interfaei care descrie implementarea conceptului abstract;
RefinedAbstraction: extinde interfaaAbstraction;
ConcreteImplementor: implementeaz interfaaImplementor;
Observaie: Un Adapter face sa funcioneze clase deja scrise; un Bridge face s
funcioneze clase care vor fi scrise!
Exemplu:
#include<vector>
#include<algorithm>
#include<string>
#include<iostream>
usingnamespacestd;
// implementation interface
classIPizzaImplementation
{
public:
voidprintIngredients()
{
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:
staticvoidprintString(strings)
{
cout <<s <<" ";
}
};
// concrete implementations
classMarguerittaImplementation : publicIPizzaImplementation
{
public:
MarguerittaImplementation()
{
ingredients.push_back("basil");
ingredients.push_back("olive oil");
}
};
classMarinaraImplementation : publicIPizzaImplementation
{
public:
MarinaraImplementation()
{
ingredients.push_back("olive oil");
ingredients.push_back("garlic");
ingredients.push_back("oregano");
}
};
classCapricciosaImplementation : publicIPizzaImplementation
{
public:
CapricciosaImplementation()
{
ingredients.push_back("olive oil");
ingredients.push_back("mushrooms");
ingredients.push_back("artichokes");
ingredients.push_back("cooked ham");
}
};
classQuattroFormaggiImplementation : publicIPizzaImplementation
{
public:
QuattroFormaggiImplementation()
{
ingredients.push_back("stracchino");
ingredients.push_back("fontina");
ingredients.push_back("gorgonzola");
}
};
// abstraction
classIPizza
{
public:
virtual voidprintIngredients() =0
{
pBody->printIngredients();
}
protected:
IPizzaImplementation* pBody;
};
// refined abstraction
classIPizzaNapoletana : publicIpizza{};
classIPizzaLazio : publicIPizza{};
classMarguerittaPizza: publicIPizzaNapoletana
{
public:
MarguerittaPizza()
{
pBody =newMarguerittaImplementation();
}
/*virtual*/ voidprintIngredients()
{
cout <<"Margueritta: ";
IPizza::printIngredients();
}
};
classMarinaraPizza: publicIPizzaNapoletana
{
public:
MarinaraPizza()
{
pBody =newMarinaraImplementation();
}
/*virtual*/ voidprintIngredients()
{
cout <<"Marinara: ";
IPizza::printIngredients();
}
};
classCapricciosaPizza: publicIPizzaLazio
{
public:
CapricciosaPizza()
{
pBody =newCapricciosaImplementation();
}
/*virtual*/ voidprintIngredients()
{
cout <<"Capricciosa: ";
IPizza::printIngredients();
}
};
classQuattroFormaggiPizza: publicIPizzaLazio
{
public:
QuattroFormaggiPizza()
{
pBody =newQuattroFormaggiImplementation();
}
/*virtual*/ voidprintIngredients()
{
cout <<"Quattro Formaggi: ";
IPizza::printIngredients();
}
};
int main()
{
IPizza* pizza[4];
pizza[0] =newMarinaraPizza;
pizza[1] =newMarguerittaPizza;
pizza[2] =newCapricciosaPizza;
pizza[3] =newQuattroFormaggiPizza;
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;
construiete ierarhii arborescente de clase, de tip parte-ntreg;
Soluie:
o clas abstract (Component) modeleaz simultan att obiectele primitive (Leaf),
ct i obiectele compuse (Composite), ceea ce permite tratarea lor n mod uniform;
Participani:
Component: declararea interfeei comune;
Composite: definete comportamentul obiectelor compuse;
Leaf: definete comportamentul obiectelor primitive;
Exemplu:
#include<iostream>
#include<vector>
usingnamespacestd;
// create an common interface
classIComponent
{
public:
virtual voidtraverse() =0;
};
// leaf
classLeaf: publicIComponent
{
int value;
public:
Leaf(int val) : value(val){}
voidtraverse()
{
cout <<value <<' ';
}
};
// composite
classComposite: publicIComponent
{
vector<IComponent*>childrens;
int value;
public:
Composite(int val) : value(val){}
voidadd(IComponent* oneChildren)
{
childrens.push_back(oneChildren);
}
voidtraverse()
{
cout <<value <<" ";
int nChildrens =childrens.size();
for (int i =0; i <nChildrens ; i++)
{
childrens[i]->traverse();
}
}
};
classRow: publicComposite
{
public:
Row(int val): Composite(val){}
voidtraverse()
{
cout <<"Row";
Composite::traverse();
}
};
classColumn: publicComposite
{
public:
Column(int val): Composite(val){}
voidtraverse()
{
cout <<"Column";
Composite::traverse();
}
};
int main()
{
RowfirstRow(1); // Row1
ColumnsecondColumn(2); // |
ColumnthirdColumn(3); // +-- Col2
RowfourthRow(4); // | |
RowfifthRow(5); // | +-- 7
// | |
firstRow.add( &secondColumn ); // +-- Col3
firstRow.add( &thirdColumn ); // | |
// | |
thirdColumn.add( &fourthRow ); // | +-- Row4
thirdColumn.add( &fifthRow ); // | | |
// | | |
firstRow.add(&Leaf(6)); // | | +-- 9
// | | |
secondColumn.add(&Leaf(7)); // | +-- Row5
thirdColumn.add(&Leaf(8)); // | | |
// | | |
fourthRow.add(&Leaf(9)); // | | +-- 10
fifthRow.add(&Leaf(10)); // | +-- 8
// | |
firstRow.traverse(); // +-- 6
cout <<endl;
return 0;
}
Decorator
Tip i scop:
ablon structural;
ataeaz, n mod dinamic, responsabiliti suplimentare unui obiect, independent
de alte instane ale aceleiai clase, ca alternativ la motenire (caracter static, se
aplic ntregii clase);
Soluie:
funcionalitatea 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 ctre un obiect LCD, cruia i deleag
atribuiile;
Participani:
Interface: declararea interfeei care descrie funcionalitatea Core;
CoreFuncionality: implementarea conceptului Core;
OptionalWrapper: descrierea conceptului de decorator
OptinalOne, OptionalTwo, OptionalThree: diverse tipuri de decorator;
Exemplu:
#include<vector>
#include<algorithm>
#include<string>
#include<iostream>
usingnamespacestd;
// interface LCD
classIPizzaNapoletana
{
public:
virtual voidprintIngredients() =0;
virtual ~IPizzaNapoletana(){}
};
// class Margueritta (Core) is a IPizzaNapoletana (LCD)
classMargueritta : publicIPizzaNapoletana
{
public:
Margueritta()
{
ingredients.push_back("mozzarella");
ingredients.push_back("tomatoes");
ingredients.push_back("basil");
ingredients.push_back("olive oil");
}
voidprintIngredients()
{
cout <<"Margueritta ingredients: ";
for_each( ingredients.begin(), ingredients.end(), printString);
cout <<endl;
}
protected: vector<string>ingredients;
private:
staticvoidprintString(strings)
{
cout <<s <<" ";
}
};
// class Decorator (is a IPizzaNapoletana )
classDecorator: publicIPizzaNapoletana
{
IPizzaNapoletana* pInnerObject;
public:
Decorator(IPizzaNapoletana* p) : pInnerObject(p){}
// delegate to base class
/*virtual*/ voidprintIngredients()
{
pInnerObject->printIngredients();
}
};
classKetchupDecorator : publicDecorator
{
public:
KetchupDecorator(IPizzaNapoletana* p): Decorator(p){}
/*virtual*/ voidprintIngredients()
{
// delegate to base class and add extra stuff
Decorator::printIngredients();
cout <<"Ketchup" <<endl;
}
};
classPepperDecorator : publicDecorator
{
public:
PepperDecorator(IPizzaNapoletana* p): Decorator(p){}
/*virtual*/ voidprintIngredients()
{
// 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 =newPepperDecorator( newKetchupDecorator( newMargueritta ) );
pPizza->printIngredients();
return 0;
}

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