Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
C++Programming/Code/DesignPatterns
Contents
1ProgrammingPatterns
1.1CreationalPatterns
1.1.1Builder
1.1.2Factory
1.1.2.1AbstractFactory
1.1.3Prototype
1.1.4Singleton
1.2StructuralPatterns
1.2.1Adapter
1.2.2Bridge
1.2.3Composite
1.2.3.1Decorator
1.2.4Facade
1.2.5Flyweight
1.2.6Proxy
1.2.7CuriouslyRecurringTemplate
1.2.8InterfacebasedProgramming(IBP)
1.3BehavioralPatterns
1.3.1ChainofResponsibility
1.3.2Command
1.3.3Interpreter
1.3.4Iterator
1.3.5Mediator
1.3.6Memento
1.3.7Observer
1.3.8State
1.3.9Strategy
1.3.10TemplateMethod
1.3.11Visitor
1.3.12ModelViewController(MVC)
ProgrammingPatterns
Softwaredesignpatternsareabstractionsthathelpstructuresystemdesigns.Whilenotnew,sincethe
conceptwasalreadydescribedbyChristopherAlexanderinitsarchitecturaltheories,itonlygatheredsome
tractioninprogrammingduetothepublicationofDesignPatterns:ElementsofReusableObjectOriented
SoftwarebookinOctober1994byErichGamma,RichardHelm,RalphJohnsonandJohnVlissides,known
astheGangofFour(GoF),thatidentifiesanddescribes23classicsoftwaredesignpatterns.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
1/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Adesignpatternisneitherastaticsolution,norisitanalgorithm.Apatternisawaytodescribeand
addressbyname(mostlyasimplisticdescriptionofitsgoal),arepeatablesolutionorapproachtoa
commondesignproblem,thatis,acommonwaytosolveagenericproblem(howgenericorcomplex,
dependsonhowrestrictedthetargetgoalis).Patternscanemergeontheirownorbydesign.Thisiswhy
designpatternsareusefulasanabstractionovertheimplementationandahelpatdesignstage.Withthis
concept,aneasierwaytofacilitatecommunicationoveradesignchoiceasnormalizationtechniqueisgiven
sothateverypersoncansharethedesignconcept.
Dependingonthedesignproblemtheyaddress,designpatternscanbeclassifiedindifferentcategories,of
whichthemaincategoriesare:
CreationalPatterns
StructuralPatterns
BehavioralPatterns.
PatternsarecommonlyfoundinobjectedorientedprogramminglanguageslikeC++orJava.Theycanbe
seenasatemplateforhowtosolveaproblemthatoccursinmanydifferentsituationsorapplications.Itis
notcodereuse,asitusuallydoesnotspecifycode,butcodecanbeeasilycreatedfromadesignpattern.
Objectorienteddesignpatternstypicallyshowrelationshipsandinteractionsbetweenclassesorobjects
withoutspecifyingthefinalapplicationclassesorobjectsthatareinvolved.
Eachdesignpatternconsistsofthefollowingparts:
Problem/requirement
Touseadesignpattern,weneedtogothroughaminianalysisdesignthatmaybecodedtotestout
thesolution.Thissectionstatestherequirementsoftheproblemwewanttosolve.Thisisusuallya
commonproblemthatwilloccurinmorethanoneapplication.
Forces
Thissectionstatesthetechnologicalboundaries,thathelpsandguidesthecreationofthesolution.
Solution
Thissectiondescribeshowtowritethecodetosolvetheaboveproblem.Thisisthedesignpartofthe
designpattern.Itmaycontainclassdiagrams,sequencediagrams,andorwhateverisneededto
describehowtocodethesolution.
Designpatternscanbeconsideredasastandardizationofcommonlyagreedbestpracticestosolvespecific
designproblems.Oneshouldunderstandthemasawaytoimplementgooddesignpatternswithin
applications.Doingsowillreducetheuseofinefficientandobscuresolutions[citationneeded].Usingdesign
patternsspeedsupyourdesignandhelpstocommunicateittootherprogrammers[citationneeded].
CreationalPatterns
Insoftwareengineering,creationaldesignpatternsaredesignpatternsthatdealwithobjectcreation
mechanisms,tryingtocreateobjectsinamannersuitabletothesituation.Thebasicformofobjectcreation
couldresultindesignproblemsoraddedcomplexitytothedesign.Creationaldesignpatternssolvethis
problembysomehowcontrollingthisobjectcreation.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
2/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Inthissectionofthebookweassumethatthereaderhasenoughfamiliaritywithfunctions,global
variables,stackvs.heap,classes,pointers,andstaticmemberfunctionsasintroducedbefore.
Aswewillseethereareseveralcreationaldesignpatterns,andallwilldealwithaspecificimplementation
task,thatwillcreateahigherlevelofabstractiontothecodebase,wewillnowcovereachone.
Builder
TheBuilderCreationalPatternisusedtoseparatetheconstructionofacomplexobjectfromits
representationsothatthesameconstructionprocesscancreatedifferentobjectsrepresentations.
Problem
Wewanttoconstructacomplexobject,howeverwedonotwanttohaveacomplexconstructor
memberoronethatwouldneedmanyarguments.
Solution
Defineanintermediateobjectwhosememberfunctionsdefinethedesiredobjectpartbypartbefore
theobjectisavailabletotheclient.BuilderPatternletsusdefertheconstructionoftheobjectuntilall
theoptionsforcreationhavebeenspecified.
#include<string>
#include<iostream>
usingnamespacestd;
//"Product"
classPizza
{
public:
voidsetDough(conststring&dough)
m_dough=dough;
voidsetSauce(conststring&sauce)
m_sauce=sauce;
voidsetTopping(conststring&topping)
m_topping=topping;
voidopen()const
cout<<"Pizzawith"<<m_dough<<"dough,"<<m_sauce<<"sauceand"
<<m_topping<<"topping.Mmm."<<endl;
private:
stringm_dough;
stringm_sauce;
stringm_topping;
};
//"AbstractBuilder"
classPizzaBuilder
{
public:
virtual~PizzaBuilder(){};
Pizza*getPizza()
{
returnm_pizza;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
3/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
voidcreateNewPizzaProduct()
m_pizza=newPizza;
virtualvoidbuildDough()=0;
virtualvoidbuildSauce()=0;
virtualvoidbuildTopping()=0;
protected:
Pizza*m_pizza;
//
classHawaiianPizzaBuilder:publicPizzaBuilder
{
public:
virtual~HawaiianPizzaBuilder(){};
};
virtualvoidbuildDough()
{
m_pizza>setDough("cross");
}
virtualvoidbuildSauce()
{
m_pizza>setSauce("mild");
}
virtualvoidbuildTopping()
{
m_pizza>setTopping("ham+pineapple");
}
classSpicyPizzaBuilder:publicPizzaBuilder
{
public:
virtual~SpicyPizzaBuilder(){};
};
virtualvoidbuildDough()
{
m_pizza>setDough("panbaked");
}
virtualvoidbuildSauce()
{
m_pizza>setSauce("hot");
}
virtualvoidbuildTopping()
{
m_pizza>setTopping("pepperoni+salami");
}
//
classCook
{
public:
voidsetPizzaBuilder(PizzaBuilder*pb)
{
m_pizzaBuilder=pb;
}
Pizza*getPizza()
{
returnm_pizzaBuilder>getPizza();
}
voidconstructPizza()
{
m_pizzaBuilder>createNewPizzaProduct();
m_pizzaBuilder>buildDough();
m_pizzaBuilder>buildSauce();
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
4/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
m_pizzaBuilder>buildTopping();
}
private:
PizzaBuilder*m_pizzaBuilder;
intmain()
{
Cookcook;
PizzaBuilder*hawaiianPizzaBuilder=newHawaiianPizzaBuilder;
PizzaBuilder*spicyPizzaBuilder=newSpicyPizzaBuilder;
cook.setPizzaBuilder(hawaiianPizzaBuilder);
cook.constructPizza();
Pizza*hawaiian=cook.getPizza();
hawaiian>open();
cook.setPizzaBuilder(spicyPizzaBuilder);
cook.constructPizza();
Pizza*spicy=cook.getPizza();
spicy>open();
deletehawaiianPizzaBuilder;
deletespicyPizzaBuilder;
deletehawaiian;
deletespicy;
}
Factory
Definition:Autilityclassthatcreatesaninstanceofaclassfromafamilyofderivedclasses
AbstractFactory
Definition:Autilityclassthatcreatesaninstanceofseveralfamiliesofclasses.Itcanalsoreturnafactory
foracertaingroup.
TheFactoryDesignPatternisusefulinasituationthatrequiresthecreationofmanydifferenttypesof
objects,allderivedfromacommonbasetype.TheFactoryMethoddefinesamethodforcreatingthe
objects,whichsubclassescanthenoverridetospecifythederivedtypethatwillbecreated.Thus,atrun
time,theFactoryMethodcanbepassedadescriptionofadesiredobject(e.g.,astringreadfromuserinput)
andreturnabaseclasspointertoanewinstanceofthatobject.Thepatternworksbestwhenawell
designedinterfaceisusedforthebaseclass,sothereisnoneedtocastthereturnedobject.
Problem
Wewanttodecideatruntimewhatobjectistobecreatedbasedonsomeconfigurationorapplication
parameter.Whenwewritethecode,wedonotknowwhatclassshouldbeinstantiated.
Solution
Defineaninterfaceforcreatinganobject,butletsubclassesdecidewhichclasstoinstantiate.Factory
Methodletsaclassdeferinstantiationtosubclasses.
Inthefollowingexample,afactorymethodisusedtocreatelaptopordesktopcomputerobjectsatruntime.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
5/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Let'sstartbydefiningComputer,whichisanabstractbaseclass(interface)anditsderivedclasses:Laptop
andDesktop.
classComputer
{
public:
virtualvoidRun()=0;
virtualvoidStop()=0;
virtual~Computer(){};/*withoutthis,youdonotcallLaptoporDesktopdestructorinthisexample!*/
};
classLaptop:publicComputer
{
public:
virtualvoidRun(){mHibernating=false;};
virtualvoidStop(){mHibernating=true;};
virtual~Laptop(){};/*becausewehavevirtualfunctions,weneedvirtualdestructor*/
private:
boolmHibernating;//Whetherornotthemachineishibernating
};
classDesktop:publicComputer
{
public:
virtualvoidRun(){mOn=true;};
virtualvoidStop(){mOn=false;};
virtual~Desktop(){};
private:
boolmOn;//Whetherornotthemachinehasbeenturnedon
};
TheactualComputerFactoryclassreturnsaComputer,givenarealworlddescriptionoftheobject.
classComputerFactory
{
public:
staticComputer*NewComputer(conststd::string&description)
{
if(description=="laptop")
returnnewLaptop;
if(description=="desktop")
returnnewDesktop;
returnNULL;
}
};
Let'sanalyzethebenefitsofthisdesign.First,thereisacompilationbenefit.Ifwemovetheinterface
Computerintoaseparateheaderfilewiththefactory,wecanthenmovetheimplementationofthe
NewComputer()functionintoaseparateimplementationfile.NowtheimplementationfileforNewComputer()
istheonlyonethatrequiresknowledgeofthederivedclasses.Thus,ifachangeismadetoanyderived
classofComputer,oranewComputersubtypeisadded,theimplementationfileforNewComputer()istheonly
filethatneedstoberecompiled.Everyonewhousesthefactorywillonlycareabouttheinterface,which
shouldremainconsistentthroughoutthelifeoftheapplication.
Also,ifthereisaneedtoaddaclass,andtheuserisrequestingobjectsthroughauserinterface,nocode
callingthefactorymayberequiredtochangetosupporttheadditionalcomputertype.Thecodeusingthe
factorywouldsimplypassonthenewstringtothefactory,andallowthefactorytohandlethenewtypes
entirely.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
6/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Imagineprogrammingavideogame,whereyouwouldliketoaddnewtypesofenemiesinthefuture,each
ofwhichhasdifferentAIfunctionsandcanupdatedifferently.Byusingafactorymethod,thecontrollerof
theprogramcancalltothefactorytocreatetheenemies,withoutanydependencyorknowledgeofthe
actualtypesofenemies.Now,futuredeveloperscancreatenewenemies,withnewAIcontrolsandnew
drawingmemberfunctions,addittothefactory,andcreatealevelwhichcallsthefactory,askingforthe
enemiesbyname.CombinethismethodwithanXMLdescriptionoflevels,anddeveloperscouldcreate
newlevelswithouthavingtorecompiletheirprogram.Allthis,thankstotheseparationofcreationof
objectsfromtheusageofobjects.
Anotherexample:
#include<stdexcept>
#include<iostream>
#include<memory>
classPizza{
public:
virtualintgetPrice()const=0;
virtual~Pizza(){};/*withoutthis,nodestructorforderivedPizza'swillbecalled.*/
};
classHamAndMushroomPizza:publicPizza{
public:
virtualintgetPrice()const{return850;};
virtual~HamAndMushroomPizza(){};
};
classDeluxePizza:publicPizza{
public:
virtualintgetPrice()const{return1050;};
virtual~DeluxePizza(){};
};
classHawaiianPizza:publicPizza{
public:
virtualintgetPrice()const{return1150;};
virtual~HawaiianPizza(){};
};
classPizzaFactory{
public:
enumPizzaType{
HamMushroom,
Deluxe,
Hawaiian
};
staticPizza*createPizza(PizzaTypepizzaType){
switch(pizzaType){
caseHamMushroom:
returnnewHamAndMushroomPizza();
caseDeluxe:
returnnewDeluxePizza();
caseHawaiian:
returnnewHawaiianPizza();
}
throw"invalidpizzatype.";
}
};
/*
*Createallavailablepizzasandprinttheirprices
*/
voidpizza_information(PizzaFactory::PizzaTypepizzatype)
{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
7/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Pizza*pizza=PizzaFactory::createPizza(pizzatype);
std::cout<<"Priceof"<<pizzatype<<"is"<<pizza>getPrice()<<std::endl;
deletepizza;
intmain()
{
pizza_information(PizzaFactory::HamMushroom);
pizza_information(PizzaFactory::Deluxe);
pizza_information(PizzaFactory::Hawaiian);
}
Prototype
Aprototypepatternisusedinsoftwaredevelopmentwhenthetypeofobjectstocreateisdeterminedbya
prototypicalinstance,whichisclonedtoproducenewobjects.Thispatternisused,forexample,whenthe
inherentcostofcreatinganewobjectinthestandardway(e.g.,usingthenewkeyword)isprohibitively
expensiveforagivenapplication.
Implementation:Declareanabstractbaseclassthatspecifiesapurevirtualclone()method.Anyclassthat
needsa"polymorphicconstructor"capabilityderivesitselffromtheabstractbaseclass,andimplementsthe
clone()operation.
Heretheclientcodefirstinvokesthefactorymethod.Thisfactorymethod,dependingontheparameter,
findsouttheconcreteclass.Onthisconcreteclass,theclone()methodiscalledandtheobjectisreturned
bythefactorymethod.
ThisissamplecodewhichisasampleimplementationofPrototypemethod.Wehavethedetailed
descriptionofallthecomponentshere.
Recordclass,whichisapurevirtualclassthathasapurevirtualmethodclone().
CarRecord,BikeRecordandPersonRecordasconcreteimplementationofaRecordclass.
AnenumRECORD_TYPE_enasonetoonemappingofeachconcreteimplementationof
Recordclass.
RecordFactoryclassthathasaFactorymethodCreateRecord().Thismethodrequiresanenum
RECORD_TYPE_enasparameteranddependingonthisparameteritreturnstheconcrete
implementationofRecordclass.
/**
*ImplementationofPrototypeMethod
**/
#include<iostream>
#include<map>
#include<string>
usingnamespacestd;
enumRECORD_TYPE_en
{
CAR,
BIKE,
PERSON
};
/**
*RecordisthebasePrototype
*/
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
8/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
classRecord
{
public:
Record(){}
virtual~Record(){}
virtualRecord*clone()=0;
virtualvoidprint()=0;
};
/**
*CarRecordisaConcretePrototype
*/
classCarRecord:publicRecord
{
private:
stringm_carName;
intm_ID;
public:
CarRecord(stringcarName,intID)
:Record()
,m_carName(carName)
,m_ID(ID)
{
}
CarRecord(constCarRecord&carRecord)
:Record(carRecord)//callthebasedefaultcopyconstructor
{
m_carName=carRecord.m_carName;
m_ID=carRecord.m_ID;
}
~CarRecord(){}
Record*clone()
{
returnnewCarRecord(*this);
}
voidprint()
{
cout<<"CarRecord"<<endl
<<"Name:"<<m_carName<<endl
<<"Number:"<<m_ID<<endl<<endl;
}
};
/**
*BikeRecordistheConcretePrototype
*/
classBikeRecord:publicRecord
{
private:
stringm_bikeName;
intm_ID;
public:
BikeRecord(stringbikeName,intID)
:Record()
,m_bikeName(bikeName)
,m_ID(ID)
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
9/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
{
}
BikeRecord(constBikeRecord&bikeRecord)
:Record(bikeRecord)
{
m_bikeName=bikeRecord.m_bikeName;
m_ID=bikeRecord.m_ID;
}
~BikeRecord(){}
Record*clone()
{
returnnewBikeRecord(*this);
}
voidprint()
{
cout<<"BikeRecord"<<endl
<<"Name:"<<m_bikeName<<endl
<<"Number:"<<m_ID<<endl<<endl;
}
};
/**
*PersonRecordistheConcretePrototype
*/
classPersonRecord:publicRecord
{
private:
stringm_personName;
intm_age;
public:
PersonRecord(stringpersonName,intage)
:Record()
,m_personName(personName)
,m_age(age)
{
}
PersonRecord(constPersonRecord&personRecord)
:Record(personRecord)
{
m_personName=personRecord.m_personName;
m_age=personRecord.m_age;
}
~PersonRecord(){}
Record*clone()
{
returnnewPersonRecord(*this);
}
voidprint()
{
cout<<"PersonRecord"<<endl
<<"Name:"<<m_personName<<endl
<<"Age:"<<m_age<<endl<<endl;
}
};
/**
*RecordFactoryistheclient
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
10/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
*/
classRecordFactory
{
private:
map<RECORD_TYPE_en,Record*>m_recordReference;
public:
RecordFactory()
{
m_recordReference[CAR]=newCarRecord("Ferrari",5050);
m_recordReference[BIKE]=newBikeRecord("Yamaha",2525);
m_recordReference[PERSON]=newPersonRecord("Tom",25);
}
~RecordFactory()
{
deletem_recordReference[CAR];
deletem_recordReference[BIKE];
deletem_recordReference[PERSON];
}
Record*createRecord(RECORD_TYPE_enenType)
{
returnm_recordReference[enType]>clone();
}
};
intmain()
{
RecordFactory*poRecordFactory=newRecordFactory();
Record*poRecord;
poRecord=poRecordFactory>createRecord(CAR);
poRecord>print();
deletepoRecord;
poRecord=poRecordFactory>createRecord(BIKE);
poRecord>print();
deletepoRecord;
poRecord=poRecordFactory>createRecord(PERSON);
poRecord>print();
deletepoRecord;
deletepoRecordFactory;
return0;
}
Anotherexample:
Toimplementthepattern,declareanabstractbaseclassthatspecifiesapurevirtualclone()member
function.Anyclassthatneedsa"polymorphicconstructor"capabilityderivesitselffromtheabstractbase
class,andimplementstheclone()operation.
Theclient,insteadofwritingcodethatinvokesthenewoperatoronahardwiredclassname,callsthe
clone()memberfunctionontheprototype,callsafactorymemberfunctionwithaparameterdesignating
theparticularconcretederivedclassdesired,orinvokestheclone()memberfunctionthroughsome
mechanismprovidedbyanotherdesignpattern.
classCPrototypeMonster
{
protected:
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
11/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
CString_name;
public:
CPrototypeMonster();
CPrototypeMonster(constCPrototypeMonster©);
virtual~CPrototypeMonster();
virtualCPrototypeMonster*Clone()const=0;//Thisforceseveryderivedclasstoprovideanoverloadforthisfuncti
voidName(CStringname);
CStringName()const;
};
classCGreenMonster:publicCPrototypeMonster
{
protected:
int_numberOfArms;
double_slimeAvailable;
public:
CGreenMonster();
CGreenMonster(constCGreenMonster©);
~CGreenMonster();
virtualCPrototypeMonster*Clone()const;
voidNumberOfArms(intnumberOfArms);
voidSlimeAvailable(doubleslimeAvailable);
intNumberOfArms()const;
doubleSlimeAvailable()const;
};
classCPurpleMonster:publicCPrototypeMonster
{
protected:
int_intensityOfBadBreath;
double_lengthOfWhiplikeAntenna;
public:
CPurpleMonster();
CPurpleMonster(constCPurpleMonster©);
~CPurpleMonster();
virtualCPrototypeMonster*Clone()const;
voidIntensityOfBadBreath(intintensityOfBadBreath);
voidLengthOfWhiplikeAntenna(doublelengthOfWhiplikeAntenna);
intIntensityOfBadBreath()const;
doubleLengthOfWhiplikeAntenna()const;
};
classCBellyMonster:publicCPrototypeMonster
{
protected:
double_roomAvailableInBelly;
public:
CBellyMonster();
CBellyMonster(constCBellyMonster©);
~CBellyMonster();
virtualCPrototypeMonster*Clone()const;
voidRoomAvailableInBelly(doubleroomAvailableInBelly);
doubleRoomAvailableInBelly()const;
};
CPrototypeMonster*CGreenMonster::Clone()const
{
returnnewCGreenMonster(*this);
}
CPrototypeMonster*CPurpleMonster::Clone()const
{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
12/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
returnnewCPurpleMonster(*this);
}
CPrototypeMonster*CBellyMonster::Clone()const
{
returnnewCBellyMonster(*this);
}
Aclientofoneoftheconcretemonsterclassesonlyneedsareference(pointer)toaCPrototypeMonster
classobjecttobeabletocalltheClonefunctionandcreatecopiesofthatobject.Thefunctionbelow
demonstratesthisconcept:
voidDoSomeStuffWithAMonster(constCPrototypeMonster*originalMonster)
{
CPrototypeMonster*newMonster=originalMonster>Clone();
ASSERT(newMonster);
newMonster>Name("MyOwnMonster");
//Addcodedoingallsortsofcoolstuffwiththemonster.
deletenewMonster;
}
NoworiginalMonstercanbepassedasapointertoCGreenMonster,CPurpleMonsterorCBellyMonster.
Singleton
TheSingletonpatternensuresthataclasshasonlyoneinstanceandprovidesaglobalpointofaccessto
thatinstance.Itisnamedafterthesingletonset,whichisdefinedtobeasetcontainingoneelement.Thisis
usefulwhenexactlyoneobjectisneededtocoordinateactionsacrossthesystem.
Checklist
Defineaprivatestaticattributeinthe"singleinstance"class.
Defineapublicstaticaccessorfunctionintheclass.
Do"lazyinitialization"(creationonfirstuse)intheaccessorfunction.
Defineallconstructorstobeprotectedorprivate.
ClientsmayonlyusetheaccessorfunctiontomanipulatetheSingleton.
Let'stakealookathowaSingletondiffersfromothervariabletypes.
Likeaglobalvariable,theSingletonexistsoutsideofthescopeofanyfunctions.Traditional
implementationusesastaticmemberfunctionoftheSingletonclass,whichwillcreateasingleinstanceof
theSingletonclassonthefirstcall,andforeverreturnthatinstance.Thefollowingcodeexampleillustrates
theelementsofaC++singletonclass,thatsimplystoresasinglestring.
classStringSingleton
{
public:
//Someaccessorfunctionsfortheclass,itself
std::stringGetString()const
{returnmString;}
voidSetString(conststd::string&newStr)
{mString=newStr;}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
13/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
//Themagicfunction,whichallowsaccesstotheclassfromanywhere
//Togetthevalueoftheinstanceoftheclass,call:
//StringSingleton::Instance().GetString();
staticStringSingleton&Instance()
{
//Thislineonlyrunsonce,thuscreatingtheonlyinstanceinexistence
staticStringSingleton*instance=newStringSingleton;
//dereferencingthevariablehere,savesthecallerfromhavingtouse
//thearrowoperator,andremovestemptationtotryanddeletethe
//returnedinstance.
return*instance;//alwaysreturnsthesameinstance
}
private:
//Weneedtomakesomegivenfunctionsprivatetofinishthedefinitionofthesingleton
StringSingleton(){}//defaultconstructoravailableonlytomembersorfriendsofthisclass
//Notethatthenexttwofunctionsarenotgivenbodies,thusanyattempt
//tocallthemimplicitlywillreturnascompilererrors.Thisprevents
//accidentalcopyingoftheonlyinstanceoftheclass.
StringSingleton(constStringSingleton&old);//disallowcopyconstructor
constStringSingleton&operator=(constStringSingleton&old);//disallowassignmentoperator
//Notethatalthoughthisshouldbeallowed,
//somecompilersmaynotimplementprivatedestructors
//Thispreventsothersfromdeletingouronesingleinstance,whichwasotherwisecreatedontheheap
~StringSingleton(){}
private://privatedataforaninstanceofthisclass
std::stringmString;
};
VariationsofSingletons:
ApplicationsofSingletonClass:
Onecommonuseofthesingletondesignpatternisforapplicationconfigurations.Configurationsmayneed
tobeaccessibleglobally,andfutureexpansionstotheapplicationconfigurationsmaybeneeded.The
subsetC'sclosestalternativewouldbetocreateasingleglobalstruct.Thishadthelackofclarityasto
wherethisobjectwasinstantiated,aswellasnotguaranteeingtheexistenceoftheobject.
Take,forexample,thesituationofanotherdeveloperusingyoursingletoninsidetheconstructoroftheir
object.Then,yetanotherdeveloperdecidestocreateaninstanceofthesecondclassintheglobalscope.If
youhadsimplyusedaglobalvariable,theorderoflinkingwouldthenmatter.Sinceyourglobalwillbe
accessed,possiblybeforemainbeginsexecuting,thereisnodefinitionastowhethertheglobalis
initialized,ortheconstructorofthesecondclassiscalledfirst.Thisbehaviorcanthenchangewithslight
modificationstootherareasofcode,whichwouldchangeorderofglobalcodeexecution.Suchanerrorcan
beveryhardtodebug.But,withuseofthesingleton,thefirsttimetheobjectisaccessed,theobjectwill
alsobecreated.Younowhaveanobjectwhichwillalwaysexist,inrelationtobeingused,andwillnever
existifneverused.
Asecondcommonuseofthisclassisinupdatingoldcodetoworkinanewarchitecture.Sincedevelopers
mayhaveusedglobalsliberally,movingthemintoasingleclassandmakingitasingleton,canbean
intermediarysteptobringtheprograminlinetostrongerobjectorientedstructure.
Anotherexample:
#include<iostream>
usingnamespacestd;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
14/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
/*Placeholderforthreadsynchronizationmutex*/
classMutex
{/*placeholderforcodetocreate,use,andfreeamutex*/
};
/*Placeholderforthreadsynchronizationlock*/
classLock
{public:
Lock(Mutex&m):mutex(m){/*placeholdercodetoacquirethemutex*/}
~Lock(){/*placeholdercodetoreleasethemutex*/}
private:
Mutex&mutex;
};
classSingleton
{public:
staticSingleton*GetInstance();
inta;
~Singleton(){cout<<"InDestructor"<<endl;}
private:
Singleton(int_a):a(_a){cout<<"InConstructor"<<endl;}
staticMutexmutex;
//Notdefined,topreventcopying
Singleton(constSingleton&);
Singleton&operator=(constSingleton&other);
};
MutexSingleton::mutex;
Singleton*Singleton::GetInstance()
{
Locklock(mutex);
cout<<"GetInstance"<<endl;
//Initializedduringfirstaccess
staticSingletoninst(1);
return&inst;
}
intmain()
{
Singleton*singleton=Singleton::GetInstance();
cout<<"Thevalueofthesingleton:"<<singleton>a<<endl;
return0;
}
StructuralPatterns
Adapter
Converttheinterfaceofaclassintoanotherinterfacethatclientsexpect.Adapterletsclassesworktogether
thatcouldn'totherwisebecauseofincompatibleinterfaces.
#include<iostream>
classMuslim{//AbstractTarget
virtual~Muslim()=default;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
15/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
virtualvoidperformsMuslimRitual()=0;
classMuslimFemale:publicMuslim{//ConcreteTarget
virtualvoidperformsMuslimRitual()override{std::cout<<"MuslimgirlperformsMuslimritual."<<std::endl;}
};
classHindu{//AbstractAdaptee
virtual~Hindu()=default;
virtualvoidperformsHinduRitual()=0;
};
classHinduFemale:publicHindu{//ConcreteAdaptee
virtualvoidperformsHinduRitual()override{std::cout<<"HindugirlperformsHinduritual."<<std::endl;}
};
classMuslimRitual{
voidcarryOutRitual(Muslim*muslim){
std::cout<<"OnwiththeMuslimrituals!"<<std::endl;
muslim>performsMuslimRitual();
}
};
classMuslimAdapter:publicMuslim{//Adapter
private:
Hindu*hindu;
public:
MuslimAdapter(Hindu*h):hindu(h){}
virtualvoidperformsMuslimRitual()override{hindu>performsHinduRitual();}
};
intmain(){//Clientcode
HinduFemale*hinduGirl=newHinduFemale;
MuslimFemale*muslimGirl=newMuslimFemale;
MuslimRitualmuslimRitual;
//
muslimRitual.carryOutRitual(hinduGirl);//WillnotcompileofcoursesincetheparametermustbeoftypeMuslim*.
MuslimAdapter*adaptedHindu=newMuslimAdapter(hinduGirl);//hinduGirlhasadaptedtobecomeaMuslim!
muslimRitual.carryOutRitual(muslimGirl);
muslimRitual.carryOutRitual(adaptedHindu);//SonowhinduGirl,intheformofadaptedHindu,participatesinthemu
//NotethathinduGirliscarryingoutherowntypeofritualinmuslimRitualthough.
deleteadaptedHindu;//adaptedHinduisnotneededanymore
}
Bridge
TheBridgePatternisusedtoseparateouttheinterfacefromitsimplementation.Doingthisgivesthe
flexibilitysothatbothcanvaryindependently.
Thefollowingexamplewilloutput:
API1.circleat1:27.5
API2.circleat5:727.5
#include<iostream>
usingnamespacestd;
/*Implementor*/
classDrawingAPI{
public:
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
16/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
virtualvoiddrawCircle(doublex,doubley,doubleradius)=0;
virtual~DrawingAPI(){}
};
/*ConcreteImplementorA*/
classDrawingAPI1:publicDrawingAPI{
public:
voiddrawCircle(doublex,doubley,doubleradius){
cout<<"API1.circleat"<<x<<':'<<y<<''<<radius<<endl;
}
};
/*ConcreteImplementorB*/
classDrawingAPI2:publicDrawingAPI{
public:
voiddrawCircle(doublex,doubley,doubleradius){
cout<<"API2.circleat"<<x<<':'<<y<<''<<radius<<endl;
}
};
/*Abstraction*/
classShape{
public:
virtual~Shape(){}
virtualvoiddraw()=0;
virtualvoidresizeByPercentage(doublepct)=0;
};
/*RefinedAbstraction*/
classCircleShape:publicShape{
public:
CircleShape(doublex,doubley,doubleradius,DrawingAPI*drawingAPI):
m_x(x),m_y(y),m_radius(radius),m_drawingAPI(drawingAPI)
{}
voiddraw(){
m_drawingAPI>drawCircle(m_x,m_y,m_radius);
}
voidresizeByPercentage(doublepct){
m_radius*=pct;
}
private:
doublem_x,m_y,m_radius;
DrawingAPI*m_drawingAPI;
};
intmain(void){
CircleShapecircle1(1,2,3,newDrawingAPI1());
CircleShapecircle2(5,7,11,newDrawingAPI2());
circle1.resizeByPercentage(2.5);
circle2.resizeByPercentage(2.5);
circle1.draw();
circle2.draw();
return0;
}
Composite
Compositeletsclientstreatindividualobjectsandcompositionsofobjectsuniformly.TheComposite
patterncanrepresentboththeconditions.Inthispattern,onecandeveloptreestructuresforrepresenting
partwholehierarchies.
#include<vector>
#include<iostream>//std::cout
#include<memory>//std::auto_ptr
#include<algorithm>//std::for_each
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
17/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
#include<functional>//std::mem_fun
usingnamespacestd;
classGraphic
{
public:
virtualvoidprint()const=0;
virtual~Graphic(){}
};
classEllipse:publicGraphic
{
public:
voidprint()const{
cout<<"Ellipse\n";
}
};
classCompositeGraphic:publicGraphic
{
public:
voidprint()const{
//foreachelementingraphicList_,calltheprintmemberfunction
for_each(graphicList_.begin(),graphicList_.end(),mem_fun(&Graphic::print));
}
voidadd(Graphic*aGraphic){
graphicList_.push_back(aGraphic);
}
private:
vector<Graphic*>graphicList_;
};
intmain()
{
//Initializefourellipses
constauto_ptr<Ellipse>ellipse1(newEllipse());
constauto_ptr<Ellipse>ellipse2(newEllipse());
constauto_ptr<Ellipse>ellipse3(newEllipse());
constauto_ptr<Ellipse>ellipse4(newEllipse());
//Initializethreecompositegraphics
constauto_ptr<CompositeGraphic>graphic(newCompositeGraphic());
constauto_ptr<CompositeGraphic>graphic1(newCompositeGraphic());
constauto_ptr<CompositeGraphic>graphic2(newCompositeGraphic());
//Composesthegraphics
graphic1>add(ellipse1.get());
graphic1>add(ellipse2.get());
graphic1>add(ellipse3.get());
graphic2>add(ellipse4.get());
graphic>add(graphic1.get());
graphic>add(graphic2.get());
//Printsthecompletegraphic(fourtimesthestring"Ellipse")
graphic>print();
return0;
}
Decorator
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
18/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Thedecoratorpatternhelpstoattachadditionalbehaviororresponsibilitiestoanobjectdynamically.
Decoratorsprovideaflexiblealternativetosubclassingforextendingfunctionality.Thisisalsocalled
Wrapper.Ifyourapplicationdoessomekindoffiltering,thenDecoratormightbegoodpatternto
considerforthejob.
#include<string>
#include<iostream>
usingnamespacestd;
classCar//OurAbstractbaseclass
{
protected:
string_str;
public:
Car()
{
_str="UnknownCar";
}
virtualstringgetDescription()
{
return_str;
}
virtualdoublegetCost()=0;
virtual~Car()
{
cout<<"~Car()\n";
}
};
classOptionsDecorator:publicCar//DecoratorBaseclass
{
public:
virtualstringgetDescription()=0;
virtual~OptionsDecorator()
{
cout<<"~OptionsDecorator()\n";
}
};
classCarModel1:publicCar
{
public:
CarModel1()
{
_str="CarModel1";
}
virtualdoublegetCost()
{
return31000.23;
}
~CarModel1()
{
cout<<"~CarModel1()\n";
}
};
classNavigation:publicOptionsDecorator
{
Car*_b;
public:
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
19/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Navigation(Car*b)
{
_b=b;
}
stringgetDescription()
{
return_b>getDescription()+",Navigation";
}
doublegetCost()
{
return300.56+_b>getCost();
}
~Navigation()
{
cout<<"~Navigation()\n";
}
};
classPremiumSoundSystem:publicOptionsDecorator
{
Car*_b;
public:
PremiumSoundSystem(Car*b)
{
_b=b;
}
stringgetDescription()
{
return_b>getDescription()+",PremiumSoundSystem";
}
doublegetCost()
{
return0.30+_b>getCost();
}
~PremiumSoundSystem()
{
cout<<"~PremiumSoundSystem()\n";
}
};
classManualTransmission:publicOptionsDecorator
{
Car*_b;
public:
ManualTransmission(Car*b)
{
_b=b;
}
stringgetDescription()
{
return_b>getDescription()+",ManualTransmission";
}
doublegetCost()
{
return0.30+_b>getCost();
}
~ManualTransmission()
{
cout<<"~ManualTransmission()\n";
}
};
classCarDecoratorExample{
public:
voidexecute()
{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
20/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
//CreateourCarthatwewanttobuy
Car*b=newCarModel1();
cout<<"Basemodelof"<<b>getDescription()<<"costs$"<<b>getCost()<<"\n";
//Whowantsbasemodelletsaddsomemorefeatures
b=newNavigation(b);
cout<<b>getDescription()<<"willcostyou$"<<b>getCost()<<"\n";
b=newPremiumSoundSystem(b);
b=newManualTransmission(b);
cout<<b>getDescription()<<"willcostyou$"<<b>getCost()<<"\n";
//WARNING!HereweleaktheCarModel1,NavigationandPremiumSoundSystem
//objects!eitherwedeletethemexplicitlyorrewritetheDecoratorstotake
//ownershipanddeletetheirCarswhendestroyed.
deleteb;
}
};
intmain()
{
CarDecoratorExampleb;
b.execute();
return0;
}
Theoutputoftheprogramaboveis:
BasemodelofCarModel1costs$31000.2
CarModel1,Navigationwillcostyou$31300.8
CarModel1,Navigation,PremiumSoundSystem,ManualTransmissionwillcostyou$31301.4
~ManualTransmission()
~OptionsDecorator()
~Car()
Anotherexample:
#include<iostream>
#include<string>
#include<memory>
classInterface{
public:
virtual~Interface(){}
virtualvoidwrite(std::string&)=0;
};
classCore:publicInterface{
public:
~Core(){std::cout<<"Coredestructorcalled.\n";}
virtualvoidwrite(std::string&text)override{};//Donothing.
};
classDecorator:publicInterface{
private:
std::unique_ptr<Interface>interface;
public:
Decorator(std::unique_ptr<Interface>c){interface=std::move(c);}
virtualvoidwrite(std::string&text)override{interface>write(text);}
};
classMessengerWithSalutation:publicDecorator{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
21/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
private:
std::stringsalutation;
public:
MessengerWithSalutation(std::unique_ptr<Interface>c,conststd::string&str):Decorator(std::move(c)),
~MessengerWithSalutation(){std::cout<<"Messengerdestructorcalled.\n";}
virtualvoidwrite(std::string&text)override{
text=salutation+"\n\n"+text;
Decorator::write(text);
classMessengerWithValediction:publicDecorator{
private:
std::stringvalediction;
public:
MessengerWithValediction(std::unique_ptr<Interface>c,conststd::string&str):Decorator(std::move(c
~MessengerWithValediction(){std::cout<<"MessengerWithValedictiondestructorcalled.\n";}
virtualvoidwrite(std::string&text)override{
Decorator::write(text);
text+="\n\n"+valediction;
}
};
intmain(){
conststd::stringsalutation="Greetings,",valediction="Sincerly,Andy";
std::stringmessage1="Thismessageisnotdecorated.",
message2="Thismessageisdecoratedwithasalutation.",
message3="Thismessageisdecoratedwithavalediction.",
message4="Thismessageisdecoratedwithasalutationandavalediction.";
std::unique_ptr<Interface>messenger1=std::make_unique<Core>();
std::unique_ptr<Interface>messenger2=std::make_unique<MessengerWithSalutation>(std::make_unique<Core
std::unique_ptr<Interface>messenger3=std::make_unique<MessengerWithValediction>(std::make_unique<Core
std::unique_ptr<Interface>messenger4=std::make_unique<MessengerWithValediction>(std::make_unique<Messenge
(std::make_unique<Core>(),salutation),valediction);
messenger1>write(message1);
std::cout<<message1<<'\n';
std::cout<<"\n\n\n";
messenger2>write(message2);
std::cout<<message2<<'\n';
std::cout<<"\n\n\n";
messenger3>write(message3);
std::cout<<message3<<'\n';
std::cout<<"\n\n\n";
messenger4>write(message4);
std::cout<<message4<<'\n';
std::cout<<"\n\n\n";
}
}
Theoutputoftheprogramaboveis:
Thismessageisnotdecorated.
Greetings,
Thismessageisdecoratedwithasalutation.
Thismessageisdecoratedwithavalediction.
Sincerly,Andy
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
22/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Greetings,
Thismessageisdecoratedwithasalutationandavalediction.
Sincerly,Andy
MessengerWithValedictiondestructorcalled.
Messengerdestructorcalled.
Coredestructorcalled.
MessengerWithValedictiondestructorcalled.
Coredestructorcalled.
Messengerdestructorcalled.
Coredestructorcalled.
Coredestructorcalled.
Facade
TheFacadePatternhidesthecomplexitiesofthesystembyprovidinganinterfacetotheclientfromwhere
theclientcanaccessthesystemonanunifiedinterface.Facadedefinesahigherlevelinterfacethatmakes
thesubsystemeasiertouse.Forinstancemakingoneclassmethodperformacomplexprocessbycalling
severalotherclasses.
/*FacadeisoneoftheeasiestpatternsIthink...Andthisisverysimpleexample.
Imagineyousetupasmarthousewhereeverythingisonremote.SototurnthelightsonyoupushlightsonbuttonAndsame
AC,Alarm,Music,etc...
Whenyouleaveahouseyouwouldneedtopusha100buttonstomakesureeverythingisoffandaregoodtogowhichcouldbe
annoyingifyouarelazylikeme
soIdefinedaFacadeforleavingandcomingback.(Facadefunctionsrepresentbuttons...)SowhenIcomeandleaveIjustma
callandittakescareofeverything...
*/
#include<string>
#include<iostream>
usingnamespacestd;
classAlarm
{
public:
voidalarmOn()
cout<<"Alarmisonandhouseissecured"<<endl;
};
voidalarmOff()
{
cout<<"Alarmisoffandyoucangointothehouse"<<endl;
}
classAc
{
public:
voidacOn()
cout<<"Acison"<<endl;
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
23/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
voidacOff()
{
cout<<"ACisoff"<<endl;
}
classTv
{
public:
voidtvOn()
cout<<"Tvison"<<endl;
voidtvOff()
{
cout<<"TVisoff"<<endl;
}
};
classHouseFacade
{
Alarmalarm;
Acac;
Tvtv;
public:
HouseFacade(){}
voidgoToWork()
{
ac.acOff();
tv.tvOff();
alarm.alarmOn();
}
voidcomeHome()
{
alarm.alarmOff();
ac.acOn();
tv.tvOn();
}
};
intmain()
{
HouseFacadehf;
//Ratherthancalling100differentonandofffunctionsthankstofacadeIonlyhave2functions...
hf.goToWork();
hf.comeHome();
}
Theoutputoftheprogramaboveis:
ACisoff
TVisoff
Alarmisonandhouseissecured
Alarmisoffandyoucangointothehouse
Acison
Tvison
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
24/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Flyweight
Thepatternforsavingmemory(basically)bysharingpropertiesofobjects.Imagineahugeamountof
similarobjectswhichallhavemostoftheirpropertiesthesame.It'snaturaltomovethesepropertiesoutof
theseobjectstosomeexternaldatastructureandprovideeachobjectwiththelinktothatdatastructure.
#include<iostream>
#include<string>
#include<vector>
#defineNUMBER_OF_SAME_TYPE_CHARS3;
/*Actualflyweightobjectsclass(declaration)*/
classFlyweightCharacter;
/*
FlyweightCharacterAbstractBuilderisaclassholdingthepropertieswhicharesharedby
manyobjects.Soinsteadofkeepingthesepropertiesinthoseobjectswekeepthemexternally,making
objectsflyweight.Seemoredetailsinthecommentsofmainfunction.
*/
classFlyweightCharacterAbstractBuilder{
FlyweightCharacterAbstractBuilder(){}
~FlyweightCharacterAbstractBuilder(){}
public:
staticstd::vector<float>fontSizes;//letsimaginethatsizesbemayoffloatingpointtype
staticstd::vector<std::string>fontNames;//fontnamemaybeofvariablelength(letstake6bytesisaverage)
};
staticvoidsetFontsAndNames();
staticFlyweightCharactercreateFlyweightCharacter(unsignedshortfontSizeIndex,
unsignedshortfontNameIndex,
unsignedshortpositionInStream);
std::vector<float>FlyweightCharacterAbstractBuilder::fontSizes(3);
std::vector<std::string>FlyweightCharacterAbstractBuilder::fontNames(3);
voidFlyweightCharacterAbstractBuilder::setFontsAndNames(){
fontSizes[0]=1.0;
fontSizes[1]=1.5;
fontSizes[2]=2.0;
fontNames[0]="first_font";
fontNames[1]="second_font";
fontNames[2]="third_font";
classFlyweightCharacter{
unsignedshortfontSizeIndex;//indexinsteadofactualfontsize
unsignedshortfontNameIndex;//indexinsteadoffontname
unsignedpositionInStream;
public:
};
FlyweightCharacter(unsignedshortfontSizeIndex,unsignedshortfontNameIndex,unsignedshortpositionInStream)
fontSizeIndex(fontSizeIndex),fontNameIndex(fontNameIndex),positionInStream(positionInStream){}
voidprint(){
std::cout<<"FontSize:"<<FlyweightCharacterAbstractBuilder::fontSizes[fontSizeIndex]
<<",fontName:"<<FlyweightCharacterAbstractBuilder::fontNames[fontNameIndex]
<<",characterstreamposition:"<<positionInStream<<std::endl;
}
~FlyweightCharacter(){}
FlyweightCharacterFlyweightCharacterAbstractBuilder::createFlyweightCharacter(unsignedshortfontSizeIndex,unsignedshort
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
25/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
FlyweightCharacterfc(fontSizeIndex,fontNameIndex,positionInStream);
returnfc;
intmain(intargc,char**argv){
std::vector<FlyweightCharacter>chars;
FlyweightCharacterAbstractBuilder::setFontsAndNames();
unsignedshortlimit=NUMBER_OF_SAME_TYPE_CHARS;
for(unsignedshorti=0;i<limit;i++){
chars.push_back(FlyweightCharacterAbstractBuilder::createFlyweightCharacter(0,0,i));
chars.push_back(FlyweightCharacterAbstractBuilder::createFlyweightCharacter(1,1,i+1*limit));
chars.push_back(FlyweightCharacterAbstractBuilder::createFlyweightCharacter(2,2,i+2*limit));
}
/*
Eachcharstoreslinkstoit'sfontNameandfontSizesowhatwegetis:
eachobjectinsteadofallocating6bytes(conventionabove)forstring
and4bytesforfloatallocates2bytesforfontNameIndexandfontSizeIndex.
Thatmeansforeachcharwesave6+422=6bytes.
NowimaginewehaveNUMBER_OF_SAME_TYPE_CHARS=1000i.e.withourcode
wewillhave3groupsofcharswhith1000charsineachgroupwhichwillsaveus
3*1000*6(3*6+3*4)=17970savedbytes.
3*6+3*4isanumberofbytesallocatedbyFlyweightCharacterAbstractBuilder.
Sotheideaofthepatternistomovepropertiessharedbymanyobjectstosome
externalcontainer.Theobjectsinthatcasedon'tstorethedatathemselvesthey
storeonlylinkstothedatawhichsavesmemoryandmaketheobjectslighter.
ThedatasizeofpropertiesstoredexternallymaybesignificantwhichwillsaveREALLY
hugeammountofmemoryandwillmakeeachobjectsuperlightincomparissontoit'scounterpart.
That'swherethenameofthepatterncomesfrom:flyweight(i.e.verylight).
*/
for(unsignedshorti=0;i<chars.size();i++){
chars[i].print();
}
std::cin.get();return0;
Proxy
TheProxyPatternwillprovideanobjectasurrogateorplaceholderforanotherobjecttocontrolaccesstoit.
Itisusedwhenyouneedtorepresentacomplexobjectwithasimplerone.Ifcreationofanobjectis
expensive,itcanbepostponeduntiltheveryneedarisesandmeanwhileasimplerobjectcanserveasa
placeholder.ThisplaceholderobjectiscalledtheProxyforthecomplexobject.
CuriouslyRecurringTemplate
Thistechniqueisknownmorewidelyasamixin.Mixinsaredescribedintheliteraturetobeapowerfultool
forexpressingabstractions[citationneeded].
InterfacebasedProgramming(IBP)
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
26/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
InterfacebasedprogrammingiscloselyrelatedwithModularProgrammingandObjectOriented
Programming,itdefinestheapplicationasacollectionofintercoupledmodules(interconnectedandwhich
plugintoeachotherviainterface).Modulescanbeunplugged,replaced,orupgraded,withouttheneedof
compromisingthecontentsofothermodules.
Thetotalsystemcomplexityisgreatlyreduced.InterfaceBasedProgrammingaddsmoretomodular
ProgramminginthatitinsiststhatInterfacesaretobeaddedtothesemodules.Theentiresystemisthus
viewedasComponentsandtheinterfacesthathelpsthemtocoact.
InterfacebasedProgrammingincreasesthemodularityoftheapplicationandhenceitsmaintainabilityata
laterdevelopmentcycles,especiallywheneachmodulemustbedevelopedbydifferentteams.Itisawell
knownmethodologythathasbeenaroundforalongtimeanditisacoretechnologybehindframeworks
suchasCORBA.
Thisisparticularlyconvenientwhenthirdpartiesdevelopadditionalcomponentsfortheestablishedsystem.
Theyjusthavetodevelopcomponentsthatsatisfytheinterfacespecifiedbytheparentapplicationvendor.
Thusthepublisheroftheinterfacesassuresthathewillnotchangetheinterfaceandthesubscriberagreesto
implementtheinterfaceaswholewithoutanydeviation.AninterfaceisthereforesaidtobeaContractual
agreementandtheprogrammingparadigmbasedonthisistermedas"interfacebasedprogramming".
BehavioralPatterns
ChainofResponsibility
ChainofResponsibilitypatternhastheintenttoavoidcouplingthesenderofarequesttoitsreceiverby
givingmorethanoneobjectachancetohandletherequest.Chainsthereceivingobjectsandpassesthe
requestsalongthechainuntilanobjecthandlesit.
Command
CommandpatternisanObjectbehavioralpatternthatdecouplessenderandreceiverbyencapsulatinga
requestasanobject,therebylettingyouparameterizeclientswithdifferentrequests,queueorlogrequests,
andsupportundoableoperations.Itcanalsobethoughtasanobjectorientedequivalentofcallback
method.
CallBack:Itisafunctionthatisregisteredtobecalledatlaterpointoftimebasedonuseractions.
#include<iostream>
usingnamespacestd;
/*theCommandinterface*/
classCommand
{
public:
virtualvoidexecute()=0;
};
/*Receiverclass*/
classLight{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
27/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
public:
Light(){}
voidturnOn()
{
cout<<"Thelightison"<<endl;
}
};
voidturnOff()
{
cout<<"Thelightisoff"<<endl;
}
/*theCommandforturningonthelight*/
classFlipUpCommand:publicCommand
{
public:
FlipUpCommand(Light&light):theLight(light)
{
virtualvoidexecute()
{
theLight.turnOn();
}
private:
Light&theLight;
};
/*theCommandforturningoffthelight*/
classFlipDownCommand:publicCommand
{
public:
FlipDownCommand(Light&light):theLight(light)
virtualvoidexecute()
theLight.turnOff();
}
private:
Light&theLight;
};
classSwitch{
public:
Switch(Command&flipUpCmd,Command&flipDownCmd)
:flipUpCommand(flipUpCmd),flipDownCommand(flipDownCmd)
voidflipUp()
{
flipUpCommand.execute();
}
voidflipDown()
{
flipDownCommand.execute();
}
private:
Command&flipUpCommand;
Command&flipDownCommand;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
28/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
};
/*Thetestclassorclient*/
intmain()
{
Lightlamp;
FlipUpCommandswitchUp(lamp);
FlipDownCommandswitchDown(lamp);
Switchs(switchUp,switchDown);
s.flipUp();
s.flipDown();
Interpreter
Givenalanguage,definearepresentationforitsgrammaralongwithaninterpreterthatusesthe
representationtointerpretsentencesinthelanguage.
#include<iostream>
#include<string>
#include<map>
#include<list>
namespacewikibooks_design_patterns
{
//
basedontheJavasamplearoundhere
typedefstd::stringString;
structExpression;
typedefstd::map<String,Expression*>Map;
typedefstd::list<Expression*>Stack;
structExpression{
virtualintinterpret(Mapvariables)=0;
virtual~Expression(){}
};
classNumber:publicExpression{
private:
intnumber;
public:
Number(intnumber){this>number=number;}
intinterpret(Mapvariables){returnnumber;}
};
classPlus:publicExpression{
Expression*leftOperand;
Expression*rightOperand;
public:
Plus(Expression*left,Expression*right){
leftOperand=left;
rightOperand=right;
}
~Plus(){
deleteleftOperand;
deleterightOperand;
}
intinterpret(Mapvariables){
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
29/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
returnleftOperand>interpret(variables)+rightOperand>interpret(variables);
}
};
classMinus:publicExpression{
Expression*leftOperand;
Expression*rightOperand;
public:
Minus(Expression*left,Expression*right){
leftOperand=left;
rightOperand=right;
}
~Minus(){
deleteleftOperand;
deleterightOperand;
}
intinterpret(Mapvariables){
returnleftOperand>interpret(variables)rightOperand>interpret(variables);
}
};
classVariable:publicExpression{
Stringname;
public:
Variable(Stringname){this>name=name;}
intinterpret(Mapvariables){
if(variables.end()==variables.find(name))return0;
returnvariables[name]>interpret(variables);
}
};
//
Whiletheinterpreterpatterndoesnotaddressparsing,aparserisprovidedforcompleteness.
classEvaluator:publicExpression{
Expression*syntaxTree;
public:
Evaluator(Stringexpression){
StackexpressionStack;
size_tlast=0;
for(size_tnext=0;String::npos!=last;last=(String::npos==next)?next:(1+next)){
next=expression.find('',last);
Stringtoken(expression.substr(last,(String::npos==next)?(expression.length()last):(nextlast)));
if(token=="+"){
Expression*right=expressionStack.back();expressionStack.pop_back();
Expression*left=expressionStack.back();expressionStack.pop_back();
Expression*subExpression=newPlus(right,left);
expressionStack.push_back(subExpression);
}
elseif(token==""){
//it'snecessaryremovefirsttherightoperandfromthestack
Expression*right=expressionStack.back();expressionStack.pop_back();
//..andaftertheleftone
Expression*left=expressionStack.back();expressionStack.pop_back();
Expression*subExpression=newMinus(left,right);
expressionStack.push_back(subExpression);
}
else
expressionStack.push_back(newVariable(token));
}
syntaxTree=expressionStack.back();expressionStack.pop_back();
}
~Evaluator(){
deletesyntaxTree;
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
30/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
intinterpret(Mapcontext){
returnsyntaxTree>interpret(context);
}
};
}
voidmain()
{
usingnamespacewikibooks_design_patterns;
Evaluatorsentence("wxz+");
static
constintsequences[][3]={
{5,10,42},{1,3,2},{7,9,5},
};
for(size_ti=0;sizeof(sequences)/sizeof(sequences[0])>i;++i){
Mapvariables;
variables["w"]=newNumber(sequences[i][0]);
variables["x"]=newNumber(sequences[i][1]);
variables["z"]=newNumber(sequences[i][2]);
intresult=sentence.interpret(variables);
for(Map::iteratorit=variables.begin();variables.end()!=it;++it)deleteit>second;
std::cout<<"Interpreterresult:"<<result<<std::endl;
Iterator
The'iterator'designpatternisusedliberallywithintheSTLfortraversalofvariouscontainers.Thefull
understandingofthiswillliberateadevelopertocreatehighlyreusableandeasily
understandable[citationneeded]datacontainers.
Thebasicideaoftheiteratoristhatitpermitsthetraversalofacontainer(likeapointermovingacrossan
array).However,togettothenextelementofacontainer,youneednotknowanythingabouthowthe
containerisconstructed.Thisistheiteratorsjob.Bysimplyusingthememberfunctionsprovidedbythe
iterator,youcanmove,intheintendedorderofthecontainer,fromthefirstelementtothelastelement.
Letusstartbyconsideringatraditionalsingledimensionalarraywithapointermovingfromthestarttothe
end.Thisexampleassumesknowledgeofpointerarithmetic.Notethattheuseof"it"or"itr,"henceforth,is
ashortversionof"iterator."
constintARRAY_LEN=42;
int*myArray=newint[ARRAY_LEN];
//Settheiteratortopointtothefirstmemorylocationofthearray
int*arrayItr=myArray;
//Movethrougheachelementofthearray,settingitequaltoitspositioninthearray
for(inti=0;i<ARRAY_LEN;++i)
{
//setthevalueofthecurrentlocationinthearray
*arrayItr=i;
//byincrementingthepointer,wemoveittothenextpositioninthearray.
//Thisiseasyforacontiguousmemorycontainer,sincepointerarithmetic
//handlesthetraversal.
++arrayItr;
}
//Donotbemessy,cleanupafteryourself
delete[]myArray;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
31/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Thiscodeworksveryquicklyforarrays,buthowwouldwetraversealinkedlist,whenthememoryisnot
contiguous?Considertheimplementationofarudimentarylinkedlistasfollows:
classIteratorCannotMoveToNext{};//Errorclass
classMyIntLList
{
public:
//TheNodeclassrepresentsasingleelementinthelinkedlist.
//Thenodehasanextnodeandapreviousnode,sothattheuser
//maymovefromonepositiontothenext,orstepbackasingle
//position.NoticethatthetraversalofalinkedlistisO(N),
//asissearching,sincethelistisnotordered.
classNode
{
public:
Node():mNextNode(0),mPrevNode(0),mValue(0){}
Node*mNextNode;
Node*mPrevNode;
intmValue;
};
MyIntLList():mSize(0)
{}
~MyIntLList()
{
while(!Empty())
pop_front();
}//Seeexpansionforfurtherimplementation;
intSize()const{returnmSize;}
//Addthisvaluetotheendofthelist
voidpush_back(intvalue)
{
Node*newNode=newNode;
newNode>mValue=value;
newNode>mPrevNode=mTail;
mTail>mNextNode=newNode;
mTail=newNode;
++mSize;
}
//Removethevaluefromthebeginningofthelist
voidpop_front()
{
if(Empty())
return;
Node*tmpnode=mHead;
mHead=mHead>mNextNode;
deletetmpnode;
mSize;
}
boolEmpty()
{returnmSize==0;}
//Thisiswheretheiteratordefinitionwillgo,
//butletsfinishthedefinitionofthelist,first
private:
Node*mHead;
Node*mTail;
intmSize;
};
Thislinkedlisthasnoncontiguousmemory,andisthereforenotacandidateforpointerarithmetic.Andwe
donotwanttoexposetheinternalsofthelisttootherdevelopers,forcingthemtolearnthem,andkeeping
usfromchangingit.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
32/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Thisiswheretheiteratorcomesin.Thecommoninterfacemakeslearningtheusageofthecontainereasier,
andhidesthetraversallogicfromotherdevelopers.
Letusexaminethecodefortheiterator,itself.
/*
*Theiteratorclassknowstheinternalsofthelinkedlist,sothatit
*maymovefromoneelementtothenext.Inthisimplementation,Ihave
*chosentheclassictraversalmethodofoverloadingtheincrement
*operators.Morethoroughimplementationsofabidirectionallinked
*listwouldincludedecrementoperatorssothattheiteratormaymove
*intheoppositedirection.
*/
classIterator
{
public:
Iterator(Node*position):mCurrNode(position){}
//Prefixincrement
constIterator&operator++()
{
if(mCurrNode==0||mCurrNode>mNextNode==0)
throwIteratorCannotMoveToNext();e
mCurrNode=mCurrNode>mNextNode;
return*this;
}
//Postfixincrement
Iteratoroperator++(int)
{
IteratortempItr=*this;
++(*this);
returntempItr;
}
//Dereferencingoperatorreturnsthecurrentnode,whichshouldthen
//bedereferencedfortheint.TODO:Checksyntaxforoverloading
//dereferencingoperator
Node*operator*()
{returnmCurrNode;}
//TODO:implementarrowoperatorandcleanupexampleusagefollowing
private:
Node*mCurrNode;
};
//Thefollowingtwofunctionsmakeitpossibletocreate
//iteratorsforaninstanceofthisclass.
//Firstpositionforiteratorsshouldbethefirstelementinthecontainer.
IteratorBegin(){returnIterator(mHead);}
//Finalpositionforiteratorsshouldbeonepastthelastelementinthecontainer.
IteratorEnd(){returnIterator(0);}
Withthisimplementation,itisnowpossible,withoutknowledgeofthesizeofthecontainerorhowitsdata
isorganized,tomovethrougheachelementinorder,manipulatingorsimplyaccessingthedata.Thisis
donethroughtheaccessorsintheMyIntLListclass,Begin()andEnd().
//Createalist
MyIntLListmyList;
//Addsomeitemstothelist
for(inti=0;i<10;++i)
myList.push_back(i);
//Movethroughthelist,adding42toeachitem.
for(MyIntLList::Iteratorit=myList.Begin();it!=myList.End();++it)
(*it)>mValue+=42;
Thefollowingprogramgivestheimplementationofaniteratordesignpatternwithagenerictemplate:
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
33/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
/************************************************************************/
/*Iterator.h*/
/************************************************************************/
#ifndefMY_ITERATOR_HEADER
#defineMY_ITERATOR_HEADER
#include<iterator>
#include<vector>
#include<set>
//////////////////////////////////////////////////////////////////////////
template<classT,classU>
classIterator
{
public:
typedeftypenamestd::vector<T>::iteratoriter_type;
Iterator(U*pData):m_pData(pData){
m_it=m_pData>m_data.begin();
voidfirst()
{
m_it=m_pData>m_data.begin();
}
voidnext()
{
m_it++;
}
boolisDone()
{
return(m_it==m_pData>m_data.end());
}
iter_typecurrent()
returnm_it;
}
private:
U*m_pData;
iter_typem_it;
};
template<classT,classU,classA>
classsetIterator
{
public:
typedeftypenamestd::set<T,U>::iteratoriter_type;
setIterator(A*pData):m_pData(pData)
m_it=m_pData>m_data.begin();
voidfirst()
{
m_it=m_pData>m_data.begin();
}
voidnext()
{
m_it++;
}
boolisDone()
{
return(m_it==m_pData>m_data.end());
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
34/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
iter_typecurrent()
{
returnm_it;
}
private:
iter_type
};
#endif
*m_pData;
m_it;
/************************************************************************/
/*Aggregate.h*/
/************************************************************************/
#ifndefMY_DATACOLLECTION_HEADER
#defineMY_DATACOLLECTION_HEADER
#include"Iterator.h"
template<classT>
classaggregate
{
friendclassIterator<T,aggregate>;
public:
voidadd(Ta)
m_data.push_back(a);
Iterator<T,aggregate>*create_iterator()
{
returnnewIterator<T,aggregate>(this);
}
private:
std::vector<T>m_data;
};
template<classT,classU>
classaggregateSet
{
friendclasssetIterator<T,U,aggregateSet>;
public:
voidadd(Ta)
m_data.insert(a);
setIterator<T,U,aggregateSet>*create_iterator()
{
returnnewsetIterator<T,U,aggregateSet>(this);
}
voidPrint()
{
copy(m_data.begin(),m_data.end(),std::ostream_iterator<T>(std::cout,"\n"));
}
private:
std::set<T,U>m_data;
};
#endif
/************************************************************************/
/*IteratorTest.cpp*/
/************************************************************************/
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
35/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
#include<iostream>
#include<string>
#include"Aggregate.h"
usingnamespacestd;
classMoney
{
public:
Money(inta=0):m_data(a){}
voidSetMoney(inta)
{
m_data=a;
}
intGetMoney()
returnm_data;
private:
intm_data;
};
className
{
public:
Name(stringname):m_name(name){}
conststring&GetName()const
{
returnm_name;
}
friendostream&operator<<(ostream&out,Namename)
{
out<<name.GetName();
returnout;
}
private:
stringm_name;
};
structNameLess
{
booloperator()(constName&lhs,constName&rhs)const
return(lhs.GetName()<rhs.GetName());
}
};
intmain()
{
//sample1
cout<<"________________Iteratorwithint______________________________________"<<endl;
aggregate<int>agg;
for(inti=0;i<10;i++)
agg.add(i);
Iterator<int,aggregate<int>>*it=agg.create_iterator();
for(it>first();!it>isDone();it>next())
cout<<*it>current()<<endl;
//sample2
aggregate<Money>agg2;
Moneya(100),b(1000),c(10000);
agg2.add(a);
agg2.add(b);
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
36/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
agg2.add(c);
cout<<"________________IteratorwithClassMoney______________________________"<<endl;
Iterator<Money,aggregate<Money>>*it2=agg2.create_iterator();
for(it2>first();!it2>isDone();it2>next())
cout<<it2>current()>GetMoney()<<endl;
//sample3
cout<<"________________SetIteratorwithClassName______________________________"<<endl;
setIterator<Name,NameLess,aggregateSet<Name,NameLess>>*it3=aset.create_iterator();
for(it3>first();!it3>isDone();it3>next())
cout<<(*it3>current())<<endl;
aggregateSet<Name,NameLess>aset;
aset.add(Name("Qmt"));
aset.add(Name("Bmt"));
aset.add(Name("Cmt"));
aset.add(Name("Amt"));
Consoleoutput:
________________Iteratorwithint______________________________________
0
1
2
3
4
5
6
7
8
9
________________IteratorwithClassMoney______________________________
100
1000
10000
________________SetIteratorwithClassName___________________________
Amt
Bmt
Cmt
Qmt
Mediator
Defineanobjectthatencapsulateshowasetofobjectsinteract.Mediatorpromotesloosecouplingby
keepingobjectsfromreferringtoeachotherexplicitly,anditletsyouvarytheirinteractionindependently.
#include<iostream>
#include<string>
#include<list>
classMediatorInterface;
classColleagueInterface{
std::stringname;
public:
ColleagueInterface(conststd::string&newName):name(newName){}
std::stringgetName()const{returnname;}
virtualvoidsendMessage(constMediatorInterface&,conststd::string&)const=0;
virtualvoidreceiveMessage(constColleagueInterface*,conststd::string&)const=0;
};
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
37/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
classColleague:publicColleagueInterface{
public:
usingColleagueInterface::ColleagueInterface;
virtualvoidsendMessage(constMediatorInterface&,conststd::string&)constoverride;
private:
virtualvoidreceiveMessage(constColleagueInterface*,conststd::string&)constoverride;
};
classMediatorInterface{
private:
std::list<ColleagueInterface*>colleagueList;
public:
conststd::list<ColleagueInterface*>&getColleagueList()const{returncolleagueList;}
virtualvoiddistributeMessage(constColleagueInterface*,conststd::string&)const=0;
virtualvoidregisterColleague(ColleagueInterface*colleague){colleagueList.emplace_back(colleague);}
};
classMediator:publicMediatorInterface{
virtualvoiddistributeMessage(constColleagueInterface*,conststd::string&)constoverride;
};
voidColleague::sendMessage(constMediatorInterface&mediator,conststd::string&message)const{
mediator.distributeMessage(this,message);
}
voidColleague::receiveMessage(constColleagueInterface*sender,conststd::string&message)const{
std::cout<<getName()<<"receivedthemessagefrom"<<sender>getName()<<":"<<message<<std::endl;
}
voidMediator::distributeMessage(constColleagueInterface*sender,conststd::string&message)const{
for(constColleagueInterface*x:getColleagueList())
if(x!=sender)//Donotsendthemessagebacktothesender
x>receiveMessage(sender,message);
}
intmain(){
Colleague*bob=newColleague("Bob"),*sam=newColleague("Sam"),*frank=newColleague("Frank"),*tom
Colleague*staff[]={bob,sam,frank,tom};
MediatormediatorStaff,mediatorSamsBuddies;
for(Colleague*x:staff)
mediatorStaff.registerColleague(x);
bob>sendMessage(mediatorStaff,"I'mquittingthisjob!");
mediatorSamsBuddies.registerColleague(frank);mediatorSamsBuddies.registerColleague(tom);//Sam'sbuddiesonly
sam>sendMessage(mediatorSamsBuddies,"Hooray!He'sgone!Let'sgoforadrink,guys!");
return0;
}
Memento
WithoutviolatingencapsulationtheMementoPatternwillcaptureandexternalizeanobjectsinternalstate
sothattheobjectcanberestoredtothisstatelater.ThoughtheGangofFourusesfriendasawayto
implementthispatternitisnotthebestdesign[citationneeded].ItcanalsobeimplementedusingPIMPL
(pointertoimplementationoropaquepointer).BestUsecaseis'UndoRedo'inaneditor.
TheOriginator(theobjecttobesaved)createsasnapshotofitselfasaMementoobject,andpassesthat
referencetotheCaretakerobject.TheCaretakerobjectkeepstheMementountilsuchatimeasthe
OriginatormaywanttoreverttoapreviousstateasrecordedintheMementoobject.
Seememoize(http://perldoc.perl.org/Memoize.html)foranoldschoolexampleofthispattern.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
38/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
conststd::stringNAME="Object";
template<typenameT>
std::stringtoString(constT&t){
std::stringstreamss;
ss<<t;
returnss.str();
}
classMemento;
classObject{
private:
intvalue;
std::stringname;
doubledecimal;//andsupposethereareloadsofotherdatamembers
public:
Object(intnewValue):value(newValue),name(NAME+toString(value)),decimal((float)value/100){}
voiddoubleValue(){value=2*value;name=NAME+toString(value);decimal=(float)value/100;}
voidincreaseByOne(){value++;name=NAME+toString(value);decimal=(float)value/100;}
intgetValue()const{returnvalue;}
std::stringgetName()const{returnname;}
doublegetDecimal()const{returndecimal;}
Memento*createMemento()const;
voidreinstateMemento(Memento*mem);
};
classMemento{
private:
Objectobject;
public:
Memento(constObject&obj):object(obj){}
Objectsnapshot()const{returnobject;}//wantasnapshotofObjectitselfbecauseofitsmanydatamembers
};
Memento*Object::createMemento()const{
returnnewMemento(*this);
}
voidObject::reinstateMemento(Memento*mem){
*this=mem>snapshot();
}
classCommand{
private:
typedefvoid(Object::*Action)();
Object*receiver;
Actionaction;
staticstd::vector<Command*>commandList;
staticstd::vector<Memento*>mementoList;
staticintnumCommands;
staticintmaxCommands;
public:
Command(Object*newReceiver,ActionnewAction):receiver(newReceiver),action(newAction){}
virtualvoidexecute(){
if(mementoList.size()<numCommands+1)
mementoList.resize(numCommands+1);
mementoList[numCommands]=receiver>createMemento();//savesthelastvalue
if(commandList.size()<numCommands+1)
commandList.resize(numCommands+1);
commandList[numCommands]=this;//savesthelastcommand
if(numCommands>maxCommands)
maxCommands=numCommands;
numCommands++;
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
39/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
(receiver>*action)();
}
staticvoidundo(){
if(numCommands==0)
{
std::cout<<"Thereisnothingtoundoatthispoint."<<std::endl;
return;
}
commandList[numCommands1]>receiver>reinstateMemento(mementoList[numCommands1]);
numCommands;
}
voidstaticredo(){
if(numCommands>maxCommands)
{
std::cout<<"Thereisnothingtoredoatthispoint."<<std::endl;
return;
}
Command*commandRedo=commandList[numCommands];
(commandRedo>receiver>*(commandRedo>action))();
numCommands++;
}
std::vector<Command*>Command::commandList;
std::vector<Memento*>Command::mementoList;
intCommand::numCommands=0;
intCommand::maxCommands=0;
intmain()
{
inti;
std::cout<<"Pleaseenteraninteger:";
std::cin>>i;
Object*object=newObject(i);
Command*commands[3];
commands[1]=newCommand(object,&Object::doubleValue);
commands[2]=newCommand(object,&Object::increaseByOne);
std::cout<<"0.Exit,1.Double,2.Increasebyone,3.Undo,4.Redo:";
std::cin>>i;
while(i!=0)
if(i==3)
Command::undo();
elseif(i==4)
Command::redo();
elseif(i>0&&i<=2)
commands[i]>execute();
else
std::cout<<"Enteraproperchoice:";
std::cin>>i;
continue;
std::cout<<""<<object>getValue()<<""<<object>getName()<<""<<object>getDecimal()<<
std::cout<<"0.Exit,1.Double,2.Increasebyone,3.Undo,4.Redo:";
std::cin>>i;
}
}
Observer
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
40/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
TheObserverPatterndefinesaonetomanydependencybetweenobjectssothatwhenoneobjectchanges
state,allitsdependentsarenotifiedandupdatedautomatically.
Problem
Inoneplaceormanyplacesintheapplicationweneedtobeawareaboutasystemeventoran
applicationstatechange.We'dliketohaveastandardwayofsubscribingtolisteningforsystem
eventsandastandardwayofnotifyingtheinterestedparties.Thenotificationshouldbeautomated
afteraninterestedpartysubscribedtothesystemeventorapplicationstatechange.Therealsoshould
beawaytounsubscribe.
Forces
Observersandobservablesprobablyshouldberepresentedbyobjects.Theobserverobjectswillbe
notifiedbytheobservableobjects.
Solution
Aftersubscribingthelisteningobjectswillbenotifiedbyawayofmethodcall.
#include<list>
#include<algorithm>
#include<iostream>
usingnamespacestd;
//TheAbstractObserver
classObserverBoardInterface
{
public:
virtualvoidupdate(floata,floatb,floatc)=0;
};
//AbstractInterfaceforDisplays
classDisplayBoardInterface
{
public:
virtualvoidshow()=0;
};
//TheAbstractSubject
classWeatherDataInterface
{
public:
virtualvoidregisterOb(ObserverBoardInterface*ob)=0;
virtualvoidremoveOb(ObserverBoardInterface*ob)=0;
virtualvoidnotifyOb()=0;
};
//TheConcreteSubject
classParaWeatherData:publicWeatherDataInterface
{
public:
voidSensorDataChange(floata,floatb,floatc)
{
m_humidity=a;
m_temperature=b;
m_pressure=c;
notifyOb();
}
voidregisterOb(ObserverBoardInterface*ob)
{
m_obs.push_back(ob);
}
voidremoveOb(ObserverBoardInterface*ob)
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
41/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
{
m_obs.remove(ob);
}
protected:
voidnotifyOb()
{
list<ObserverBoardInterface*>::iteratorpos=m_obs.begin();
while(pos!=m_obs.end())
{
((ObserverBoardInterface*)(*pos))>update(m_humidity,m_temperature,m_pressure);
(dynamic_cast<DisplayBoardInterface*>(*pos))>show();
++pos;
}
}
private:
floatm_humidity;
floatm_temperature;
floatm_pressure;
list<ObserverBoardInterface*>m_obs;
};
//AConcreteObserver
classCurrentConditionBoard:publicObserverBoardInterface,publicDisplayBoardInterface
{
public:
CurrentConditionBoard(ParaWeatherData&a):m_data(a)
{
m_data.registerOb(this);
}
voidshow()
{
cout<<"_____CurrentConditionBoard_____"<<endl;
cout<<"humidity:"<<m_h<<endl;
cout<<"temperature:"<<m_t<<endl;
cout<<"pressure:"<<m_p<<endl;
cout<<"_______________________________"<<endl;
}
voidupdate(floath,floatt,floatp)
{
m_h=h;
m_t=t;
m_p=p;
}
private:
floatm_h;
floatm_t;
floatm_p;
ParaWeatherData&m_data;
};
//AConcreteObserver
classStatisticBoard:publicObserverBoardInterface,publicDisplayBoardInterface
{
public:
StatisticBoard(ParaWeatherData&a):m_maxt(1000),m_mint(1000),m_avet(0),m_count(0),m_data(a)
{
m_data.registerOb(this);
}
voidshow()
{
cout<<"________StatisticBoard_________"<<endl;
cout<<"lowesttemperature:"<<m_mint<<endl;
cout<<"highesttemperature:"<<m_maxt<<endl;
cout<<"averagetemperature:"<<m_avet<<endl;
cout<<"_______________________________"<<endl;
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
42/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
voidupdate(floath,floatt,floatp)
{
++m_count;
if(t>m_maxt)
{
m_maxt=t;
}
if(t<m_mint)
{
m_mint=t;
}
m_avet=(m_avet*(m_count1)+t)/m_count;
}
private:
floatm_maxt;
floatm_mint;
floatm_avet;
intm_count;
ParaWeatherData&m_data;
};
intmain(intargc,char*argv[])
{
ParaWeatherData*wdata=newParaWeatherData;
CurrentConditionBoard*currentB=newCurrentConditionBoard(*wdata);
StatisticBoard*statisticB=newStatisticBoard(*wdata);
wdata>SensorDataChange(10.2,28.2,1001);
wdata>SensorDataChange(12,30.12,1003);
wdata>SensorDataChange(10.2,26,806);
wdata>SensorDataChange(10.3,35.9,900);
wdata>removeOb(currentB);
wdata>SensorDataChange(100,40,1900);
deletestatisticB;
deletecurrentB;
deletewdata;
return0;
}
State
TheStatePatternallowsanobjecttoalteritsbehaviorwhenitsinternalstatechanges.Theobjectwill
appearashavingchangeditsclass.
#include<iostream>
#include<string>
#include<cstdlib>
#include<ctime>
#include<memory>
enumInput{DUCK_DOWN,STAND_UP,JUMP,DIVE};
classFighter;
classStandingState;classJumpingState;classDivingState;
classFighterState{
public:
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
43/53
10/14/2015
};
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
staticstd::shared_ptr<StandingState>standing;
staticstd::shared_ptr<DivingState>diving;
virtual~FighterState()=default;
virtualvoidhandleInput(Fighter&,Input)=0;
virtualvoidupdate(Fighter&)=0;
classDuckingState:publicFighterState{
private:
intchargingTime;
staticconstintFullRestTime=5;
public:
DuckingState():chargingTime(0){}
virtualvoidhandleInput(Fighter&,Input)override;
virtualvoidupdate(Fighter&)override;
};
classStandingState:publicFighterState{
public:
virtualvoidhandleInput(Fighter&,Input)override;
virtualvoidupdate(Fighter&)override;
};
classJumpingState:publicFighterState{
private:
intjumpingHeight;
public:
JumpingState(){jumpingHeight=std::rand()%5+1;}
virtualvoidhandleInput(Fighter&,Input)override;
virtualvoidupdate(Fighter&)override;
};
classDivingState:publicFighterState{
public:
virtualvoidhandleInput(Fighter&,Input)override;
virtualvoidupdate(Fighter&)override;
};
std::shared_ptr<StandingState>FighterState::standing(newStandingState);
std::shared_ptr<DivingState>FighterState::diving(newDivingState);
classFighter{
private:
std::stringname;
std::shared_ptr<FighterState>state;
intfatigueLevel=std::rand()%10;
public:
Fighter(conststd::string&newName):name(newName),state(FighterState::standing){}
std::stringgetName()const{returnname;}
intgetFatigueLevel()const{returnfatigueLevel;}
virtualvoidhandleInput(Inputinput){state>handleInput(*this,input);}//delegateinputhandlingto's
voidchangeState(std::shared_ptr<FighterState>newState){state=newState;updateWithNewState();}
voidstandsUp(){std::cout<<getName()<<"standsup."<<std::endl;}
voidducksDown(){std::cout<<getName()<<"ducksdown."<<std::endl;}
voidjumps(){std::cout<<getName()<<"jumpsintotheair."<<std::endl;}
voiddives(){std::cout<<getName()<<"makesadiveattackinthemiddleofthejump!"<<std::endl;}
voidfeelsStrong(){std::cout<<getName()<<"feelsstrong!"<<std::endl;}
voidchangeFatigueLevelBy(intchange){fatigueLevel+=change;std::cout<<"fatigueLevel="<<fatigueLev
private:
virtualvoidupdateWithNewState(){state>update(*this);}//delegateupdatingto'state'
};
voidStandingState::handleInput(Fighter&fighter,Inputinput){
switch(input){
caseSTAND_UP:std::cout<<fighter.getName()<<"remainsstanding."<<std::endl;return;
caseDUCK_DOWN:fighter.changeState(std::shared_ptr<DuckingState>(newDuckingState));returnfighter
caseJUMP:fighter.jumps();returnfighter.changeState(std::shared_ptr<JumpingState>(newJumpingState
default:std::cout<<"Onecannotdothatwhilestanding."<<fighter.getName()<<"remainsstandingbyd
}
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
44/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
voidStandingState::update(Fighter&fighter){
if(fighter.getFatigueLevel()>0)
fighter.changeFatigueLevelBy(1);
}
voidDuckingState::handleInput(Fighter&fighter,Inputinput){
switch(input){
caseSTAND_UP:fighter.changeState(FighterState::standing);returnfighter.standsUp();
caseDUCK_DOWN:
std::cout<<fighter.getName()<<"remainsinduckingposition,";
if(chargingTime<FullRestTime)std::cout<<"recoveringinthemeantime."<<std::endl;
elsestd::cout<<"fullyrecovered."<<std::endl;
returnupdate(fighter);
default:
std::cout<<"Onecannotdothatwhileducking."<<fighter.getName()<<"remainsinduckingposit
update(fighter);
}
}
voidDuckingState::update(Fighter&fighter){
chargingTime++;
std::cout<<"Chargingtime="<<chargingTime<<"."<<std::endl;
if(fighter.getFatigueLevel()>0)
fighter.changeFatigueLevelBy(1);
if(chargingTime>=FullRestTime&&fighter.getFatigueLevel()<=3)
fighter.feelsStrong();
}
voidJumpingState::handleInput(Fighter&fighter,Inputinput){
switch(input){
caseDIVE:fighter.changeState(FighterState::diving);returnfighter.dives();
default:
std::cout<<"Onecannotdothatinthemiddleofajump."<<fighter.getName()<<"landsfromhis
fighter.changeState(FighterState::standing);
}
}
voidJumpingState::update(Fighter&fighter){
std::cout<<fighter.getName()<<"hasjumped"<<jumpingHeight<<"feetintotheair."<<std::endl;
if(jumpingHeight>=3)
fighter.changeFatigueLevelBy(1);
}
voidDivingState::handleInput(Fighter&fighter,Input){
std::cout<<"Regardlessofwhattheuserinputis,"<<fighter.getName()<<"landsfromhisdiveandisnowstandi
fighter.changeState(FighterState::standing);
}
voidDivingState::update(Fighter&fighter){
fighter.changeFatigueLevelBy(2);
}
intmain(){
std::srand(std::time(nullptr));
Fighterrex("RextheFighter"),borg("BorgtheFighter");
std::cout<<rex.getName()<<"and"<<borg.getName()<<"arecurrentlystanding."<<std::endl;
intchoice;
autochooseAction=[&choice](Fighter&fighter){
std::cout<<std::endl<<DUCK_DOWN+1<<")Duckdown"<<STAND_UP+1<<")Standup"<<JUMP+
<<")Jump"<<DIVE+1<<")Diveinthemiddleofajump"<<std::endl;
std::cout<<"Choicefor"<<fighter.getName()<<"?";
std::cin>>choice;
constInputinput1=static_cast<Input>(choice1);
fighter.handleInput(input1);
};
while(true){
chooseAction(rex);
chooseAction(borg);
}
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
45/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
Strategy
Definesafamilyofalgorithms,encapsulateseachone,andmaketheminterchangeable.Strategyletsthe
algorithmvaryindependentlyfromclientswhouseit.
#include<iostream>
usingnamespacestd;
classStrategyInterface
{
public:
virtualvoidexecute()const=0;
};
classConcreteStrategyA:publicStrategyInterface
{
public:
virtualvoidexecute()const
{
cout<<"CalledConcreteStrategyAexecutemethod"<<endl;
}
};
classConcreteStrategyB:publicStrategyInterface
{
public:
virtualvoidexecute()const
{
cout<<"CalledConcreteStrategyBexecutemethod"<<endl;
}
};
classConcreteStrategyC:publicStrategyInterface
{
public:
virtualvoidexecute()const
{
cout<<"CalledConcreteStrategyCexecutemethod"<<endl;
}
};
classContext
{
private:
StrategyInterface*strategy_;
public:
explicitContext(StrategyInterface*strategy):strategy_(strategy)
{
}
voidset_strategy(StrategyInterface*strategy)
{
strategy_=strategy;
}
voidexecute()const
{
strategy_>execute();
}
};
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
46/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
intmain(intargc,char*argv[])
{
ConcreteStrategyAconcreteStrategyA;
ConcreteStrategyBconcreteStrategyB;
ConcreteStrategyCconcreteStrategyC;
ContextcontextA(&concreteStrategyA);
ContextcontextB(&concreteStrategyB);
ContextcontextC(&concreteStrategyC);
contextA.execute();//output:"CalledConcreteStrategyAexecutemethod"
contextB.execute();//output:"CalledConcreteStrategyBexecutemethod"
contextC.execute();//output:"CalledConcreteStrategyCexecutemethod"
contextA.set_strategy(&concreteStrategyB);
contextA.execute();//output:"CalledConcreteStrategyBexecutemethod"
contextA.set_strategy(&concreteStrategyC);
contextA.execute();//output:"CalledConcreteStrategyCexecutemethod"
return0;
}
TemplateMethod
Bydefiningaskeletonofanalgorithminanoperation,deferringsomestepstosubclasses,theTemplate
Methodletssubclassesredefinecertainstepsofthatalgorithmwithoutchangingthealgorithm'sstructure.
#include<ctime>
#include<assert.h>
#include<iostream>
namespacewikibooks_design_patterns
{
/**
*Anabstractclassthatiscommontoseveralgamesin
*whichplayersplayagainsttheothers,butonlyoneis
*playingatagiventime.
*/
classGame{
public:
Game():playersCount(0),movesCount(0),playerWon(1)
{
srand((unsigned)time(NULL));
}
/*Atemplatemethod:*/
voidplayOneGame(constintplayersCount=0){
if(playersCount)
this>playersCount=playersCount;
InitializeGame();
assert(this>playersCount);
intj=0;
while(!endOfGame()){
makePlay(j);
j=(j+1)%this>playersCount;
if(!j){
++movesCount;
}
}
printWinner();
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
47/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
}
protected:
virtualvoidinitializeGame()=0;
virtualvoidmakePlay(intplayer)=0;
virtualboolendOfGame()=0;
virtualvoidprintWinner()=0;
private:
voidInitializeGame()
{
movesCount=0;
playerWon=1;
initializeGame();
protected:
intplayersCount;
intmovesCount;
intplayerWon;
};
//Nowwecanextendthisclassinorder
//toimplementactualgames:
classMonopoly:publicGame{
/*Implementationofnecessaryconcretemethods*/
voidinitializeGame(){
//Initializeplayers
playersCount=rand()*7/RAND_MAX+2;
//Initializemoney
}
voidmakePlay(intplayer){
//Processoneturnofplayer
//
Decidewinner
if(movesCount<20)
return;
constintchances=(movesCount>199)?199:movesCount;
constintrandom=MOVES_WIN_CORRECTION*rand()*200/RAND_MAX;
if(random<chances)
playerWon=player;
}
boolendOfGame(){
//Returntrueifgameisover
//accordingtoMonopolyrules
return(1!=playerWon);
}
voidprintWinner(){
assert(playerWon>=0);
assert(playerWon<playersCount);
//Displaywhowon
std::cout<<"Monopoly,player"<<playerWon<<"wonin"<<movesCount<<"moves."<<std::endl;
}
private:
enum
{
MOVES_WIN_CORRECTION=20,
};
};
classChess:publicGame{
/*Implementationofnecessaryconcretemethods*/
voidinitializeGame(){
//Initializeplayers
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
48/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
playersCount=2;
//Putthepiecesontheboard
}
voidmakePlay(intplayer){
assert(player<playersCount);
//Processaturnfortheplayer
//
decidewinner
if(movesCount<2)
return;
constintchances=(movesCount>99)?99:movesCount;
constintrandom=MOVES_WIN_CORRECTION*rand()*100/RAND_MAX;
//std::cout<<random<<":"<<chances<<std::endl;
if(random<chances)
playerWon=player;
}
boolendOfGame(){
//ReturntrueifinCheckmateor
//Stalematehasbeenreached
return(1!=playerWon);
}
voidprintWinner(){
assert(playerWon>=0);
assert(playerWon<playersCount);
//Displaythewinningplayer
std::cout<<"Player"<<playerWon<<"wonin"<<movesCount<<"moves."<<std::endl;
}
private:
enum
{
MOVES_WIN_CORRECTION=7,
};
};
}
intmain()
{
usingnamespacewikibooks_design_patterns;
Game*game=NULL;
Chesschess;
game=&chess;
for(unsignedi=0;i<100;++i)
game>playOneGame();
Monopolymonopoly;
game=&monopoly;
for(unsignedi=0;i<100;++i)
game>playOneGame();
return0;
}
Visitor
TheVisitorPatternwillrepresentanoperationtobeperformedontheelementsofanobjectstructureby
lettingyoudefineanewoperationwithoutchangingtheclassesoftheelementsonwhichitoperates.
#include<string>
#include<iostream>
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
49/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
#include<vector>
usingnamespacestd;
classWheel;
classEngine;
classBody;
classCar;
//interfacetoallcar'parts'
structCarElementVisitor
{
virtualvoidvisit(Wheel&wheel)const=0;
virtualvoidvisit(Engine&engine)const=0;
virtualvoidvisit(Body&body)const=0;
virtualvoidvisitCar(Car&car)const=0;
virtual~CarElementVisitor(){};
};
//interfacetoonepart
structCarElement
{
virtualvoidaccept(constCarElementVisitor&visitor)=0;
virtual~CarElement(){}
};
//wheelelement,therearefourwheelswithuniquenames
classWheel:publicCarElement
{
public:
explicitWheel(conststring&name):
name_(name)
{
}
conststring&getName()const
{
returnname_;
}
voidaccept(constCarElementVisitor&visitor)
{
visitor.visit(*this);
}
private:
stringname_;
};
//engine
classEngine:publicCarElement
{
public:
voidaccept(constCarElementVisitor&visitor)
{
visitor.visit(*this);
}
};
//body
classBody:publicCarElement
{
public:
voidaccept(constCarElementVisitor&visitor)
{
visitor.visit(*this);
}
};
//car,allcarelements(parts)together
classCar
{
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
50/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
public:
vector<CarElement*>&getElements()
{
returnelements_;
}
Car()
{
//assumethatneitherpush_backnorWheel(conststring&)maythrow
elements_.push_back(newWheel("frontleft"));
elements_.push_back(newWheel("frontright"));
elements_.push_back(newWheel("backleft"));
elements_.push_back(newWheel("backright"));
elements_.push_back(newBody());
elements_.push_back(newEngine());
}
~Car()
{
for(vector<CarElement*>::iteratorit=elements_.begin();
it!=elements_.end();++it)
{
delete*it;
}
}
private:
vector<CarElement*>elements_;
};
//PrintVisitorandDoVisitorshowbyusingadifferentimplementationtheCarclassisunchanged
//eventhoughthealgorithmisdifferentinPrintVisitorandDoVisitor.
classCarElementPrintVisitor:publicCarElementVisitor
{
public:
voidvisit(Wheel&wheel)const
{
cout<<"Visiting"<<wheel.getName()<<"wheel"<<endl;
}
voidvisit(Engine&engine)const
{
cout<<"Visitingengine"<<endl;
}
voidvisit(Body&body)const
{
cout<<"Visitingbody"<<endl;
}
voidvisitCar(Car&car)const
{
cout<<endl<<"Visitingcar"<<endl;
vector<CarElement*>&elems=car.getElements();
for(vector<CarElement*>::iteratorit=elems.begin();
it!=elems.end();++it)
{
(*it)>accept(*this);
//thisissuesthecallbacki.e.tothisfromtheelement
}
cout<<"Visitedcar"<<endl;
}
};
classCarElementDoVisitor:publicCarElementVisitor
{
public:
//thesearespecificimplementationsaddedtotheoriginalobjectwithoutmodifyingtheoriginalstruct
voidvisit(Wheel&wheel)const
{
cout<<"Kickingmy"<<wheel.getName()<<"wheel"<<endl;
}
voidvisit(Engine&engine)const
{
cout<<"Startingmyengine"<<endl;
}
voidvisit(Body&body)const
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
51/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
{
cout<<"Movingmybody"<<endl;
}
voidvisitCar(Car&car)const
{
cout<<endl<<"Startingmycar"<<endl;
vector<CarElement*>&elems=car.getElements();
for(vector<CarElement*>::iteratorit=elems.begin();
it!=elems.end();++it)
{
(*it)>accept(*this);
//thisissuesthecallbacki.e.tothisfromtheelement
}
cout<<"Stoppedcar"<<endl;
}
};
intmain()
{
Carcar;
CarElementPrintVisitorprintVisitor;
CarElementDoVisitordoVisitor;
printVisitor.visitCar(car);
doVisitor.visitCar(car);
return0;
}
ModelViewController(MVC)
Apatternoftenusedbyapplicationsthatneedtheabilitytomaintainmultipleviewsofthesamedata.The
modelviewcontrollerpatternwasuntilrecently[citationneeded]averycommonpatternespeciallyfor
graphicuserinterlaceprogramming,itsplitsthecodein3pieces.Themodel,theview,andthecontroller.
TheModelistheactualdatarepresentation(forexample,ArrayvsLinkedList)orotherobjects
representingadatabase.TheViewisaninterfacetoreadingthemodelorafatclientGUI.TheController
providestheinterfaceofchangingormodifyingthedata,andthenselectingthe"NextBestView"(NBV).
Newcomerswillprobablyseethis"MVC"modelaswasteful,mainlybecauseyouareworkingwithmany
extraobjectsatruntime,whenitseemslikeonegiantobjectwilldo.ButthesecrettotheMVCpatternis
notwritingthecode,butinmaintainingit,andallowingpeopletomodifythecodewithoutchangingmuch
else.Also,keepinmind,thatdifferentdevelopershavedifferentstrengthsandweaknesses,soteam
buildingaroundMVCiseasier.ImagineaViewTeamthatisresponsibleforgreatviews,aModelTeam
thatknowsalotaboutdata,andaControllerTeamthatseethebigpictureofapplicationflow,handing
requests,workingwiththemodel,andselectingthemostappropriatenextviewforthatclient.
Forexample:Anaivecentraldatabasecanbeorganizedusingonlya"model",forexample,astraightarray.
However,lateron,itmaybemoreapplicabletousealinkedlist.Allarrayaccesseswillhavetoberemade
intotheirrespectiveLinkedListform(forexample,youwouldchangemyarray[5]intomylist.at(5)or
whateverisequivalentinthelanguageyouuse).
Well,ifwefollowedtheMVCpattern,thecentraldatabasewouldbeaccessedusingsomesortofa
function,forexample,myarray.at(5).Ifwechangethemodelfromanarraytoalinkedlist,allwehaveto
doischangetheviewwiththemodel,andthewholeprogramischanged.Keeptheinterfacethesamebut
changetheunderpinningsofit.Thiswouldallowustomakeoptimizationsmorefreelyandquicklythan
before.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
52/53
10/14/2015
C++Programming/Code/DesignPatternsWikibooks,openbooksforanopenworld
OneofthegreatadvantagesoftheModelViewControllerPatternisobviouslytheabilitytoreusethe
application'slogic(whichisimplementedinthemodel)whenimplementingadifferentview.Agood
exampleisfoundinwebdevelopment,whereacommontaskistoimplementanexternalAPIinsideofan
existingpieceofsoftware.IftheMVCpatternhascleanlybeenfollowed,thisonlyrequiresmodificationto
thecontroller,whichcanhavetheabilitytorenderdifferenttypesofviewsdependentonthecontenttype
requestedbytheuseragent.
Retrievedfrom"https://en.wikibooks.org/w/index.php?
title=C%2B%2B_Programming/Code/Design_Patterns&oldid=2989441"
Thispagewaslastmodifiedon2September2015,at19:38.
TextisavailableundertheCreativeCommonsAttributionShareAlikeLicense.additionaltermsmay
apply.Byusingthissite,youagreetotheTermsofUseandPrivacyPolicy.
https://en.wikibooks.org/w/index.php?title=C%2B%2B_Programming/Code/Design_Patterns&printable=yes
53/53