Sei sulla pagina 1di 205

Design Patterns

Arranged by Marko iak


Note: all content in this book can be found at
http://sourcemaking.com/design_patterns
Novi ad! "#$#.
2 of 205
Table of Contents
Introduction............................................................................................................1
%ses of &esign 'atterns...............................................................................................................$
(riticism......................................................................................................................................)
*argets the +rong problem..........................................................................................................)
,acks formal foundations.............................................................................................................)
,eads to inefficient solutions.......................................................................................................)
&oes not differ significantly from other abstractions..................................................................)
Creational patterns.................................................................................................5
-ntroduction..................................................................................................................................
Abstract /actory &esign 'attern..................................................................................................0
'roblem........................................................................................................................................0
&iscussion....................................................................................................................................0
tructure......................................................................................................................................0
12ample.......................................................................................................................................3
(heck list.....................................................................................................................................4
5ules of thumb.............................................................................................................................4
6uilder &esign 'attern...............................................................................................................$0
/actory Method &esign 'attern................................................................................................."4
7b8ect 'ool &esign 'attern........................................................................................................)0
'rototype &esign 'attern...........................................................................................................9$
ingleton &esign 'attern............................................................................................................$
Structural patterns...............................................................................................58
-ntroduction................................................................................................................................4
Adapter &esign 'attern...............................................................................................................:
6ridge &esign 'attern................................................................................................................04
(omposite &esign 'attern.........................................................................................................4#
&ecorator &esign 'attern..........................................................................................................:$
/acade &esign 'attern...............................................................................................................:9
/ly+eight &esign 'attern.........................................................................................................$#"
'ro2y &esign 'attern...............................................................................................................$$"
Behaioral patterns.............................................................................................122
-ntroduction.............................................................................................................................$""
(hain of 5esponsibility............................................................................................................$"9
(ommand &esign 'attern........................................................................................................$)"
-nterpreter &esign 'attern......................................................................................................$9)
-terator &esign 'attern............................................................................................................$.0
Mediator &esign 'attern..........................................................................................................$00
Memento &esign 'attern.........................................................................................................$30
Null 7b8ect &esign 'attern......................................................................................................$4"
7bserver &esign 'attern..........................................................................................................$49
tate &esign 'attern................................................................................................................$43
trategy &esign 'attern...........................................................................................................$4:
*emplate Method &esign 'attern............................................................................................$:$
;isitor &esign 'attern..............................................................................................................$:9
Introduction ! of 205
-n soft+are engineering! a design pattern is a general repeatable solution to a commonly
occurring problem in soft+are design. A design pattern isn<t a finished design that can be
transformed directly into code. -t is a description or template for ho+ to solve a problem that can
be used in many different situations.
Introduction
"ses of Design Patterns
&esign patterns can speed up the development process by providing tested! proven development
paradigms. 1ffective soft+are design re=uires considering issues that may not become visible
until later in the implementation. 5eusing design patterns helps to prevent subtle issues that can
cause ma8or problems and improves code readability for coders and architects familiar +ith the
patterns.
7ften! people only understand ho+ to apply certain soft+are design techni=ues to certain
problems. *hese techni=ues are difficult to apply to a broader range of problems. &esign patterns
provide general solutions! documented in a format that doesn<t re=uire specifics tied to a
particular problem.
-n addition! patterns allo+ developers to communicate using +ell>kno+n! +ell understood names
for soft+are interactions. (ommon design patterns can be improved over time! making them
more robust than ad>hoc designs.
Creational design patterns
*his design patterns is all about class instantiation. *his pattern can be further divided into class>
creation patterns and ob8ect>creational patterns. ?hile class>creation patterns use inheritance
effectively in the instantiation process! ob8ect>creation patterns use delegation effectively to get
the 8ob done.
#bstract $actor%
(reates an instance of several families of classes
Builder
eparates ob8ect construction from its representation
$actor% &ethod
(reates an instance of several derived classes
'b(ect Pool
Avoid e2pensive ac=uisition and release of resources by recycling ob8ects that are no
longer in use
Protot%pe
A fully initiali@ed instance to be copied or cloned
Singleton
A class of +hich only a single instance can e2ist
Introduction ) of 205
Structural design patterns
*his design patterns is all about (lass and 7b8ect composition. tructural class>creation patterns
use inheritance to compose interfaces. tructural ob8ect>patterns define +ays to compose ob8ects
to obtain ne+ functionality.
#dapter
Match interfaces of different classes
Bridge
eparates an ob8ectAs interface from its implementation
Co*posite
A tree structure of simple and composite ob8ects
Decorator
Add responsibilities to ob8ects dynamically
$acade
A single class that represents an entire subsystem
$l%+eight
A fine>grained instance used for efficient sharing
Priate Class Data
5estricts accessor/mutator access
Pro,%
An ob8ect representing another ob8ect
Behaioral design patterns
*his design patterns is all about (lass<s ob8ects communication. 6ehavioral patterns are those
patterns that are most specifically concerned +ith communication bet+een ob8ects.
Chain of responsibilit%
A +ay of passing a re=uest bet+een a chain of ob8ects
Co**and
1ncapsulate a command re=uest as an ob8ect
Interpreter
A +ay to include language elements in a program
Iterator
e=uentially access the elements of a collection
&ediator
&efines simplified communication bet+een classes
&e*ento
Introduction 5 of 205
(apture and restore an ob8ect<s internal state
-ull 'b(ect
&esigned to act as a default value of an ob8ect
'bserer
A +ay of notifying change to a number of classes
State
Alter an ob8ect<s behavior +hen its state changes
Strateg%
1ncapsulates an algorithm inside a class
Te*plate *ethod
&efer the e2act steps of an algorithm to a subclass
.isitor
&efines a ne+ operation to a class +ithout change
Criticis*
*he concept of design patterns has been critici@ed by some in the field of computer science.
Targets the +rong proble*
*he need for patterns results from using computer languages or techni=ues +ith insufficient
abstraction ability. %nder ideal factoring! a concept should not be copied! but merely referenced.
6ut if something is referenced instead of copied! then there is no BpatternB to label and catalog.
'aul Craham +rites in the essay 5evenge of the Nerds.
'eter Norvig provides a similar argument. De demonstrates that $0 out of the ") patterns in the
&esign 'atterns book E+hich is primarily focused on (FFG are simplified or eliminated Evia direct
language supportG in ,isp or &ylan.
/ac0s for*al foundations
*he study of design patterns has been e2cessively ad hoc! and some have argued that the concept
sorely needs to be put on a more formal footing. At oopsla $:::! the Cang of /our +ere E+ith
their full cooperationG sub8ected to a sho+ trial! in +hich they +ere BchargedB +ith numerous
crimes against computer science. *hey +ere BconvictedB by H of the B8urorsB +ho attended the
trial.
/eads to inefficient solutions
*he idea of a design pattern is an attempt to standardi@e +hat are already accepted best
practices. -n principle this might appear to be beneficial! but in practice it often results in the
unnecessary duplication of code. -t is almost al+ays a more efficient solution to use a +ell>
factored implementation rather than a B8ust barely good enoughB design pattern.
Does not differ significantl% fro* other abstractions
ome authors allege that design patterns don<t differ significantly from other forms of
Introduction 1 of 205
abstraction! and that the use of ne+ terminology Eborro+ed from the architecture communityG to
describe e2isting phenomena in the field of programming is unnecessary. *he Model>;ie+>
(ontroller paradigm is touted as an e2ample of a BpatternB +hich predates the concept of Bdesign
patternsB by several years. -t is further argued by some that the primary contribution of the
&esign 'atterns community Eand the Cang of /our bookG +as the use of Ale2ander<s pattern
language as a form of documentationI a practice +hich is often ignored in the literature.
Creational patterns 2 of 205
Creational patterns
Introduction
-n soft+are engineering! creational design patterns are design patterns that deal +ith ob8ect
creation mechanisms! trying to create ob8ects in a manner suitable to the situation. *he basic
form of ob8ect creation could result in design problems or added comple2ity to the design.
(reational design patterns solve this problem by someho+ controlling this ob8ect creation.
#bstract $actor%
(reates an instance of several families of classes
Builder
eparates ob8ect construction from its representation
$actor% &ethod
(reates an instance of several derived classes
'b(ect Pool
Avoid e2pensive ac=uisition and release of resources by recycling ob8ects that are no
longer in use
Protot%pe
A fully initiali@ed instance to be copied or cloned
Singleton
A class of +hich only a single instance can e2ist
3ules of thu*b
$. ometimes creational patterns are competitors: there are cases +hen either 'rototype or
Abstract /actory could be used profitably. At other times they are complementory:
Abstract /actory might store a set of 'rototypes from +hich to clone and return product
ob8ects! 6uilder can use one of the other patterns to implement +hich components get
built. Abstract /actory! 6uilder! and 'rototype can use ingleton in their implementation.
". Abstract /actory! 6uilder! and 'rototype define a factory ob8ect thatAs responsible for
kno+ing and creating the class of product ob8ects! and make it a parameter of the system.
Abstract /actory has the factory ob8ect producing ob8ects of several classes. 6uilder has
the factory ob8ect building a comple2 product incrementally using a correspondingly
comple2 protocol. 'rototype has the factory ob8ect Eaka prototypeG building a product by
copying a prototype ob8ect.
). Abstract /actory classes are often implemented +ith /actory Methods! but they can also
be implemented using 'rototype.
9. Abstract /actory can be used as an alternative to /acade to hide platform>specific classes.
.. 6uilder focuses on constructing a comple2 ob8ect step by step. Abstract /actory
emphasi@es a family of product ob8ects Eeither simple or comple2G. 6uilder returns the
product as a final step! but as far as the Abstract /actory is concerned! the product gets
returned immediately.
Creational patterns 8 of 205
0. 6uilder is to creation as trategy is to algorithm.
3. 6uilder often builds a (omposite.
4. /actory Methods are usually called +ithin *emplate methods.
:. /actory Method: creation through inheritance. 'rototype: creation through delegation.
$#. 7ften! designs start out using /actory Method Eless complicated! more customi@able!
subclasses proliferateG and evolve to+ard Abstract /actory! 'rototype! or 6uilder Emore
fle2ible! more comple2G as the designer discovers +here more fle2ibility is needed.
$$. 'rototype doesnAt re=uire subclassing! but it does re=uire an -nitiali@e operation. /actory
Method re=uires subclassing! but doesnAt re=uire -nitiali@e.
$". &esigns that make heavy use of the (omposite and &ecorator patterns often can benefit
from 'rototype as +ell.
#bstract $actor% Design Pattern
Intent
'rovide an interface for creating families of related or dependent ob8ects +ithout specifying their
concrete classes.
A hierarchy that encapsulates: many possible JplatformsK! and the construction of a suite of
JproductsK.
*he ne+ operator considered harmful.
Proble*
-f an application is to be portable! it needs to encapsulate platform dependencies. *hese
JplatformsK might include: +indo+ing system! operating system! database! etc. *oo often! this
encapsulatation is not engineered in advance! and lots of Lifdef case statements +ith options for
all currently supported platforms begin to procreate like rabbits throughout the code.
Discussion
'rovide a level of indirection that abstracts the creation of families of related or dependent
ob8ects +ithout directly specifying their concrete classes. *he JfactoryK ob8ect has the
responsibility for providing creation services for the entire platform family. (lients never create
platform ob8ects directly! they ask the factory to do that for them.
*his mechanism makes e2changing product families easy because the specific class of the factory
ob8ect appears only once in the application > +here it is instantiated. *he application can
+holesale replace the entire family of products simply by instantiating a different concrete
instance of the abstract factory.
6ecause the service provided by the factory ob8ect is so pervasive! it is routinely implemented as
a ingleton.
Structure
*he Abstract /actory defines a /actory Method per product. 1ach /actory Method encapsulates
the ne+ operator and the concrete! platform>specific! product classes. 1ach JplatformK is then
modeled +ith a /actory derived class.
Creational patterns 4 of 205
5,a*ple
*he purpose of the Abstract /actory is to provide an interface for creating families of related
ob8ects! +ithout specifying concrete classes. *his pattern is found in the sheet metal stamping
e=uipment used in the manufacture of Mapanese automobiles. *he stamping e=uipment is an
Abstract /actory +hich creates auto body parts. *he same machinery is used to stamp right hand
doors! left hand doors! right front fenders! left front fenders! hoods! etc. for different models of
cars. *hrough the use of rollers to change the stamping dies! the concrete classes produced by
the machinery can be changed +ithin three minutes.
Creational patterns 10 of 205
Chec0 list
&ecide if Jplatform independenceK and creation services are the current source of pain.
Map out a matri2 of JplatformsK versus JproductsK.
&efine a factory interface that consists of a factory method per product.
&efine a factory derived class for each platform that encapsulates all references to the ne+
operator.
*he client should retire all references to ne+! and use the factory methods to create the product
ob8ects.
3ules of thu*b
ometimes creational patterns are competitors: there are cases +hen either 'rototype or
Abstract /actory could be used profitably. At other times they are complementary: Abstract
/actory might store a set of 'rototypes from +hich to clone and return product ob8ects! 6uilder
can use one of the other patterns to implement +hich components get built. Abstract /actory!
6uilder! and 'rototype can use ingleton in their implementation.
Abstract /actory! 6uilder! and 'rototype define a factory ob8ect thatAs responsible for kno+ing
and creating the class of product ob8ects! and make it a parameter of the system. Abstract
/actory has the factory ob8ect producing ob8ects of several classes. 6uilder has the factory ob8ect
building a comple2 product incrementally using a correspondingly comple2 protocol. 'rototype
has the factory ob8ect Eaka prototypeG building a product by copying a prototype ob8ect.
Abstract /actory classes are often implemented +ith /actory Methods! but they can also be
implemented using 'rototype.
Abstract /actory can be used as an alternative to /acade to hide platform>specific classes.
6uilder focuses on constructing a comple2 ob8ect step by step. Abstract /actory emphasi@es a
family of product ob8ects Eeither simple or comple2G. 6uilder returns the product as a final step!
but as far as the Abstract /actory is concerned! the product gets returned immediately.
7ften! designs start out using /actory Method Eless complicated! more customi@able! subclasses
proliferateG and evolve to+ard Abstract /actory! 'rototype! or 6uilder Emore fle2ible! more
comple2G as the designer discovers +here more fle2ibility is needed.
#bstract $actor% in C66
#include <iostream.h>
class Shape {
public:
Shape() {
id_ = total_++;
}
virtual void draw() = 0;
protected:
int id_;
static int total_;
};
int Shape::total_ = 0;
class Circle : public Shape {
Creational patterns 11 of 205
public:
void draw() {
cout << "circle " << id_ << ": draw" << endl;
}
};
class Square : public Shape {
public:
void draw() {
cout << "square " << id_ << ": draw" << endl;
}
};
class Ellipse : public Shape {
public:
void draw() {
cout << "ellipse " << id_ << ": draw" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() {
cout << "rectangle " << id_ << ": draw" << endl;
}
};
class Factory {
public:
virtual Shape* createCurvedInstance() = 0;
virtual Shape* createStraightInstance() = 0;
};
class SimpleShapeFactory : public Factory {
public:
Shape* createCurvedInstance() {
return new Circle;
}
Shape* createStraightInstance() {
return new Square;
}
};
class RobustShapeFactory : public Factory {
public:
Shape* createCurvedInstance() {
return new Ellipse;
}
Shape* createStraightInstance() {
return new Rectangle;
}
};
int main() {
#ifdef SIMPLE
Factory* factory = new SimpleShapeFactory;
#elif ROBUST
Factory* factory = new RobustShapeFactory;
Creational patterns 12 of 205
#endif
Shape* shapes[3];
shapes[0] = factory->createCurvedInstance(); // shapes[0] = new Ellipse;
shapes[1] = factory->createStraightInstance(); // shapes[1] = new Rectangle;
shapes[2] = factory->createCurvedInstance(); // shapes[2] = new Ellipse;
for (int i=0; i < 3; i++) {
shapes[i]->draw();
}
}
output:
ellipse 0: draw
rectangle 1: draw
ellipse 2: draw
#bstract $actor% in C667 Before and after
*rying to maintain portability across multiple JplatformsK routinely re=uires lots of preprocessor
JcaseK statements. *he /actory pattern suggests defining a creation services interface in a
/actory base class! and implementing each JplatformK in a separate /actory derived class.
Before
*he client creates JproductK ob8ects directly! and must embed all possible platform permutations
in nasty looking code.
#define MOTIF
class Widget {
public:
virtual void draw() = 0;
};
class MotifButton : public Widget {
public:
void draw() { cout << "MotifButton\n"; }
};
class MotifMenu : public Widget {
public:
void draw() { cout << "MotifMenu\n"; }
};
class WindowsButton : public Widget {
public:
void draw() { cout << "WindowsButton\n"; }
};
class WindowsMenu : public Widget {
public:
void draw() { cout << "WindowsMenu\n"; }
};
Creational patterns 1! of 205
void display_window_one() {
#ifdef MOTIF
Widget* w[] = { new MotifButton,
new MotifMenu };
#else // WINDOWS
Widget* w[] = { new WindowsButton,
new WindowsMenu };
#endif
w[0]->draw(); w[1]->draw();
}
void display_window_two() {
#ifdef MOTIF
Widget* w[] = { new MotifMenu,
new MotifButton };
#else // WINDOWS
Widget* w[] = { new WindowsMenu,
new WindowsButton };
#endif
w[0]->draw(); w[1]->draw();
}
int main() {
#ifdef MOTIF
Widget* w = new MotifButton;
#else // WINDOWS
Widget* w = new WindowsButton;
#endif
w->draw();
display_window_one();
display_window_two();
}
output:
MotifButton
MotifButton
MotifMenu
MotifMenu
MotifButton
#fter
*he client: creates a platform> specific JfactoryK ob8ect! is careful to esche+ use of Jne+K! and
delegates all creation re=uests to the factory.
#define WINDOWS
class Widget {
public:
virtual void draw() = 0;
};
class MotifButton : public Widget {
public:
Creational patterns 1) of 205
void draw() { cout << "MotifButton\n"; }
};
class MotifMenu : public Widget {
public:
void draw() { cout << "MotifMenu\n"; }
};
class WindowsButton : public Widget {
public:
void draw() { cout << "WindowsButton\n"; }
};
class WindowsMenu : public Widget {
public:
void draw() { cout << "WindowsMenu\n"; }
};
class Factory {
public:
virtual Widget* create_button() = 0;
virtual Widget* create_menu() = 0;
};
class MotifFactory : public Factory {
public:
Widget* create_button() {
return new MotifButton; }
Widget* create_menu() {
return new MotifMenu; }
};
class WindowsFactory : public Factory {
public:
Widget* create_button() {
return new WindowsButton; }
Widget* create_menu() {
return new WindowsMenu; }
};
Factory* factory;
void display_window_one() {
Widget* w[] = { factory->create_button(),
factory->create_menu() };
w[0]->draw(); w[1]->draw();
}
void display_window_two() {
Widget* w[] = { factory->create_menu(),
factory->create_button() };
w[0]->draw(); w[1]->draw();
}
int main() {
#ifdef MOTIF
factory = new MotifFactory;
#else // WINDOWS
Creational patterns 15 of 205
factory = new WindowsFactory;
#endif
Widget* w = factory->create_button();
w->draw();
display_window_one();
display_window_two();
}
output:
WindowsButton
WindowsButton
WindowsMenu
WindowsMenu
WindowsButton
#bstract $actor% in 8aa
Abstract /actory classes are often implemented +ith /actory Methods! but they can also be
implemented using 'rototype. Abstract /actory might store a set of 'rototypes from +hich to
clone and return product ob8ects.
/actory Method: creation through inheritance.
'rototype: creation through delegation.
;irtual constructor: defer choice of ob8ect to create until run>time.
public class FactoryFmProto
{
static class Expression
{
protected String str;
public Expression(String s)
{
str = s;
}
public Expression cloan()
{
return null;
}
public String toString()
{
return str;
}
}
static abstract class Factory
{
protected Expression prototype = null;
public Expression makePhrase()
{
return prototype.cloan();
}
public abstract Expression makeCompromise();
Creational patterns 11 of 205
public abstract Expression makeGrade();
}
static class PCFactory extends Factory
{
public PCFactory()
{
prototype = new PCPhrase();
}
public Expression makeCompromise()
{
return new Expression("\"do it your way, any way, or no way\"");
}
public Expression makeGrade()
{
return new Expression("\"you pass, self-esteem intact\"");
}
}
static class NotPCFactory extends Factory
{
public NotPCFactory()
{
prototype = new NotPCPhrase();
}
public Expression makeCompromise()
{
return new Expression("\"my way, or the highway\"");
}
public Expression makeGrade()
{
return new Expression("\"take test, deal with the results\"");
}
}
public static void main(String[] args)
{
Factory factory;
if (args.length > 0)
factory = new PCFactory();
else
factory = new NotPCFactory();
for (int i = 0; i < 3; i++)
System.out.print(factory.makePhrase() + " ");
System.out.println();
System.out.println(factory.makeCompromise());
System.out.println(factory.makeGrade());
}
static class PCPhrase extends Expression
{
static String[] list =
{
"\"animal companion\"", "\"vertically challenged\"",
"\"factually inaccurate\"", "\"chronologically gifted\""
};
Creational patterns 12 of 205
private static int next = 0;
public PCPhrase()
{
super(list[next]);
next = (next + 1) % list.length;
}
public Expression cloan()
{
return new PCPhrase();
}
}
static class NotPCPhrase extends Expression
{
private static String[] list =
{
"\"pet\"", "\"short\"", "\"lie\"", "\"old\""
};
private static int next = 0;
public NotPCPhrase()
{
super(list[next]);
next = (next + 1) % list.length;
}
public Expression cloan()
{
return new NotPCPhrase();
}
}
}
output:
D:\Java\patterns> java FactoryFmProto
"short" "lie" "old"
"my way, or the highway"
"take test, deal with the results"
D:\Java\patterns> java FactoryFmProto 1
"vertically challenged" "factually inaccurate" "chronologically gifted"
"do it your way, any way, or no way"
"you pass, self-esteem intact"
#bstract $actor% in 8aa 2
public abstract class CPU
{
...
} // class CPU
class EmberCPU extends CPU
{
...
} // class EmberCPU
class EmberToolkit extends ArchitectureToolkit
Creational patterns 18 of 205
{
public CPU createCPU()
{
return new EmberCPU();
} // createCPU()
public MMU createMMU()
{
return new EmberMMU();
} // createMMU()
...
} // class EmberFactory
public abstract class ArchitectureToolkit
{
private static final EmberToolkit emberToolkit = new EmberToolkit();
private static final EnginolaToolkit enginolaToolkit = new EnginolaToolkit();
...
// Returns a concrete factory object that is an instance of the
// concrete factory class appropriate for the given architecture.
static final ArchitectureToolkit getFactory(int architecture)
{
switch (architecture)
{
case ENGINOLA:
return enginolaToolkit;
case EMBER:
return emberToolkit;
...
} // switch
String errMsg = Integer.toString(architecture);
throw new IllegalArgumentException(errMsg);
} // getFactory()
public abstract CPU createCPU();
public abstract MMU createMMU();
...
} // AbstractFactory

public class Client
{
public void doIt()
{
AbstractFactory af;
af = AbstractFactory.getFactory(AbstractFactory.EMBER);
CPU cpu = af.createCPU();
...
} // doIt
} // class Client
Builder Design Pattern
Creational patterns 14 of 205
Intent
eparate the construction of a comple2 ob8ect from its representation so that the same
construction process can create different representations.
'arse a comple2 representation! create one of several targets.
Proble*
An application needs to create the elements of a comple2 aggregate. *he specification for the
aggregate e2ists on secondary storage and one of many representations needs to be built in
primary storage.
Discussion
eparate the algorithm for interpreting Ei.e. reading and parsingG a stored persistence
mechanism Ee.g. 5*/ filesG from the algorithm for building and representing one of many target
products Ee.g. A(--! *eN! te2t +idgetG. *he focus/distinction is on creating comple2 aggregates.
*he JdirectorK invokes JbuilderK services as it interprets the e2ternal format. *he JbuilderK
creates part of the comple2 ob8ect each time it is called and maintains all intermediate state.
?hen the product is finished! the client retrieves the result from the JbuilderK.
Affords finer control over the construction process. %nlike creational patterns that construct
products in one shot! the 6uilder pattern constructs the product step by step under the control of
the JdirectorK.
Structure
*he 5eader encapsulates the parsing of the common input. *he 6uilder hierarchy makes possible
the polymorphic creation of many peculiar representations or targets.
Creational patterns 20 of 205
5,a*ple
*he 6uilder pattern separates the construction of a comple2 ob8ect from its representation so
that the same construction process can create different representations. *his pattern is used by
fast food restaurants to construct childrenAs meals. (hildrenAs meals typically consist of a main
item! a side item! a drink! and a toy Ee.g.! a hamburger! fries! (oke! and toy dinosaurG. Note that
there can be variation in the content of the childrenAs meal! but the construction process is the
same. ?hether a customer orders a hamburger! cheeseburger! or chicken! the process is the
same. *he employee at the counter directs the cre+ to assemble a main item! side item! and toy.
*hese items are then placed in a bag. *he drink is placed in a cup and remains outside of the bag.
*his same process is used at competing restaurants.
Chec0 list
$. &ecide if a common input and many possible representations Eor outputsG is the problem
at hand.
". 1ncapsulate the parsing of the common input in a 5eader class.
). &esign a standard protocol for creating all possible output representations. (apture the
steps of this protocol in a 6uilder interface.
9. &efine a 6uilder derived class for each target representation.
.. *he client creates a 5eader ob8ect and a 6uilder ob8ect! and registers the latter +ith the
former.
0. *he client asks the 5eader to JconstructK.
3. *he client asks the 6uilder to return the result.
3ules of thu*b
ometimes creational patterns are complementory: 6uilder can use one of the other
patterns to implement +hich components get built. Abstract /actory! 6uilder! and
'rototype can use ingleton in their implementations.
6uilder focuses on constructing a comple2 ob8ect step by step. Abstract /actory
emphasi@es a family of product ob8ects Eeither simple or comple2G. 6uilder returns the
Creational patterns 21 of 205
product as a final step! but as far as the Abstract /actory is concerned! the product gets
returned immediately.
6uilder often builds a (omposite.
7ften! designs start out using /actory Method Eless complicated! more customi@able!
subclasses proliferateG and evolve to+ard Abstract /actory! 'rototype! or 6uilder Emore
fle2ible! more comple2G as the designer discovers +here more fle2ibility is needed.
Builder in C66
Builder design pattern de*o
&iscussion. *he forte of 6uilder is constructing a comple2 ob8ect step by step. An abstract base
class declares the standard construction process! and concrete derived classes define the
appropriate implementation for each step of the process. -n this e2ample! Jdistributed +ork
packagesK have been abstracted to be persistent and platform independent.
*his means that the platform>specific mechanism for implementing files! =ueues! and
concurrency path+ays is defined in each platformAs concrete derived class. A single JreaderK
ob8ect Ei.e. parserG retrieves the archived specification for a &istr?ork'ackage and proceeds to
delegate each build step to the builder ob8ect that +as registered by the client. %pon completion!
the client retrieves the end result from the builder.
#include <iostream.h>
#include <stdio.h>
#include <string.h>
enum PersistenceType
{
File, Queue, Pathway
};
struct PersistenceAttribute
{
PersistenceType type;
char value[30];
};
class DistrWorkPackage
{
public:
DistrWorkPackage(char *type)
{
sprintf(_desc, "Distributed Work Package for: %s", type);
}
void setFile(char *f, char *v)
{
sprintf(_temp, "\n File(%s): %s", f, v);
strcat(_desc, _temp);
}
void setQueue(char *q, char *v)
{
sprintf(_temp, "\n Queue(%s): %s", q, v);
strcat(_desc, _temp);
}
void setPathway(char *p, char *v)
Creational patterns 22 of 205
{
sprintf(_temp, "\n Pathway(%s): %s", p, v);
strcat(_desc, _temp);
}
const char *getState()
{
return _desc;
}
private:
char _desc[200], _temp[80];
};
class Builder
{
public:
virtual void configureFile(char*) = 0;
virtual void configureQueue(char*) = 0;
virtual void configurePathway(char*) = 0;
DistrWorkPackage *getResult()
{
return _result;
}
protected:
DistrWorkPackage *_result;
};
class UnixBuilder: public Builder
{
public:
UnixBuilder()
{
_result = new DistrWorkPackage("Unix");
}
void configureFile(char *name)
{
_result->setFile("flatFile", name);
}
void configureQueue(char *queue)
{
_result->setQueue("FIFO", queue);
}
void configurePathway(char *type)
{
_result->setPathway("thread", type);
}
};
class VmsBuilder: public Builder
{
public:
VmsBuilder()
{
_result = new DistrWorkPackage("Vms");
}
void configureFile(char *name)
{
Creational patterns 2! of 205
_result->setFile("ISAM", name);
}
void configureQueue(char *queue)
{
_result->setQueue("priority", queue);
}
void configurePathway(char *type)
{
_result->setPathway("LWP", type);
}
};
class Reader
{
public:
void setBuilder(Builder *b)
{
_builder = b;
}
void construct(PersistenceAttribute[], int);
private:
Builder *_builder;
};
void Reader::construct(PersistenceAttribute list[], int num)
{
for (int i = 0; i < num; i++)
if (list[i].type == File)
_builder->configureFile(list[i].value);
else if (list[i].type == Queue)
_builder->configureQueue(list[i].value);
else if (list[i].type == Pathway)
_builder->configurePathway(list[i].value);
}
const int NUM_ENTRIES = 6;
PersistenceAttribute input[NUM_ENTRIES] =
{
{
File, "state.dat"
}
,
{
File, "config.sys"
}
,
{
Queue, "compute"
}
,
{
Queue, "log"
}
,
{
Pathway, "authentication"
Creational patterns 2) of 205
}
,
{
Pathway, "error processing"
}
};
int main()
{
UnixBuilder unixBuilder;
VmsBuilder vmsBuilder;
Reader reader;
reader.setBuilder(&unixBuilder);
reader.construct(input, NUM_ENTRIES);
cout << unixBuilder.getResult()->getState() << endl;
reader.setBuilder(&vmsBuilder);
reader.construct(input, NUM_ENTRIES);
cout << vmsBuilder.getResult()->getState() << endl;
}
output:
Distributed Work Package for: Unix
File(flatFile): state.dat
File(flatFile): config.sys
Queue(FIFO): compute Queue(FIFO): log
Pathway(thread): authentication
Pathway(thread): error processing
Distributed Work Package for: Vms
File(ISAM): state.dat
File(ISAM): config.sys
Queue(priority): compute
Queue(priority): log
Pathway(LWP): authentication
Pathway(LWP): error processing
Builder in 8aa7 Before and after
Before
*his implementation is arguably preferable. 1ach table class encapsulates a different layout.
class JTable_Table
{
private JTable m_table;
public JTable_Table(String[][] matrix)
{
m_table = new JTable(matrix[0].length, matrix.length);
TableModel model = m_table.getModel();
for (int i = 0; i < matrix.length; ++i)
for (int j = 0; j < matrix[i].length; ++j)
model.setValueAt(matrix[i][j], j, i);
Creational patterns 25 of 205
}
public Component get_table()
{
return m_table;
}
}
class GridLayout_Table
{
private JPanel m_table = new JPanel();
public GridLayout_Table(String[][] matrix)
{
m_table.setLayout(new GridLayout(matrix[0].length, matrix.length));
m_table.setBackground(Color.white);
for (int i = 0; i < matrix[i].length; ++i)
for (int j = 0; j < matrix.length; ++j)
m_table.add(new Label(matrix[j][i]));
}
public Component get_table()
{
return m_table;
}
}
class GridBagLayout_Table
{
private JPanel m_table = new JPanel();
public GridBagLayout_Table(String[][] matrix)
{
GridBagConstraints c = new GridBagConstraints();
m_table.setLayout(new GridBagLayout());
m_table.setBackground(Color.white);
for (int i = 0; i < matrix.length; ++i)
for (int j = 0; j < matrix[i].length; ++j)
{
c.gridx = i;
c.gridy = j;
m_table.add(new Label(matrix[i][j]), c);
}
}
public Component get_table()
{
return m_table;
}
}
public class BuilderDemo
{
public static String[][] read_data_file(String file_name)
{
String[][] matrix = null;
try
{
BufferedReader br = new BufferedReader(new FileReader(file_name));
Creational patterns 21 of 205
String line, cell = "";
String[] tokens;
boolean first_line = true;
int row = 0, col = 0;
while ((line = br.readLine()) != null)
{
// Use "whitespace" to tokenize each line
// java.sun.com/docs/books/tutorial/extra/
// regex/pre_char_classes.html
tokens = line.split("\\s");
int i = 0;
if (first_line)
{
matrix = new String[Integer.parseInt(tokens[0])
][Integer.parseInt(tokens[1])];
i = 2;
first_line = false;
}
for (; i < tokens.length; ++i)
if (tokens[i].equals(""))
{
matrix[col][row++] = cell;
cell = "";
col = 0;
}
else if (tokens[i].equals(""))
{
matrix[col++][row] = cell;
cell = "";
}
else
{
cell += " " + tokens[i];
}
}
matrix[col][row] = cell;
br.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
return matrix;
}
public static void main(String[] args)
{
JFrame frame = new JFrame("BuilderDemo - " + args[0]);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[][] matrix = read_data_file("BuilderDemo.dat");
if (args[0].equals("JTable_Table"))
frame.getContentPane().add(new JTable_Table(matrix).get_table());
else if (args[0].equals("GridLayout_Table"))
frame.getContentPane().add(new GridLayout_Table(matrix).get_table());
else if (args[0].equals("GridBagLayout_Table"))
frame.getContentPane().add(new GridBagLayout_Table(matrix).get_table()
);
Creational patterns 22 of 205
frame.pack();
frame.setVisible(true);
}
}
#fter
*he mainEG creates a reader/parser! and configures it +ith a builder Ean ob8ect that implements a
standard interface and kno+s ho+ to create one of many possible JresultsK. *he reader reads and
parses the common input and delegates the construction to the configured builder.
*his implementation demonstrates the spirit of the 6uilder pattern! but it is more intricate! and
probably cannot be 8ustified for this fairly limited conte2t.
class Reader
{
private Builder m_builder;
public Reader(Builder b)
{
m_builder = b;
}
public void construct(String file_name)
{
try
{
BufferedReader br = new BufferedReader(new FileReader(file_name));
String line, cell = "";
String[] tokens;
boolean first_line = true;
while ((line = br.readLine()) != null)
{
tokens = line.split("\\s");
int i = 0;
if (first_line)
{
m_builder.set_width_and_height(Integer.parseInt(tokens[0]),
Integer.parseInt(tokens[1]));
i = 2;
first_line = false;
}
for (; i < tokens.length; ++i)
if (tokens[i].equals(""))
{
m_builder.build_cell(cell);
cell = "";
m_builder.start_row();
}
else if (tokens[i].equals(""))
{
m_builder.build_cell(cell);
cell = "";
}
else
Creational patterns 28 of 205
{
cell += " " + tokens[i];
}
}
m_builder.build_cell(cell);
br.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
interface Builder
{
void set_width_and_height(int width, int height);
void start_row();
void build_cell(String value);
Component get_result();
}
class JTable_Builder implements Builder
{
private JTable m_table;
private TableModel m_model;
private int i = 0, j = 0;
public void set_width_and_height(int width, int height)
{
m_table = new JTable(height, width);
m_model = m_table.getModel();
}
public void start_row()
{
++i;
j = 0;
}
public void build_cell(String value)
{
m_model.setValueAt(value, i, j++);
}
public Component get_result()
{
return m_table;
}
}
class GridLayout_Builder implements Builder
{
private JPanel m_panel = new JPanel();
public void set_width_and_height(int width, int height)
{
m_panel.setLayout(new GridLayout(height, width));
m_panel.setBackground(Color.white);
Creational patterns 24 of 205
}
public void start_row(){}
public void build_cell(String value)
{
m_panel.add(new Label(value));
}
public Component get_result()
{
return m_panel;
}
}
class GridBagLayout_Builder implements Builder
{
private JPanel m_panel = new JPanel();
private GridBagConstraints c = new GridBagConstraints();
private int i = 0, j = 0;
public void set_width_and_height(int width, int height)
{
m_panel.setLayout(new GridBagLayout());
m_panel.setBackground(Color.white);
}
public void start_row()
{
++i;
j = 0;
}
public void build_cell(String value)
{
c.gridx = j++;
c.gridy = i;
m_panel.add(new Label(value), c);
}
public Component get_result()
{
return m_panel;
}
}
public class BuilderDemo
{
public static void main(String[] args)
{
Builder target = null;
try
{
target = (Builder)Class.forName(args[0]).newInstance();
}
catch (Exception ex)
{
ex.printStackTrace();
}
Reader parser = new Reader(target);
parser.construct("BuilderDemo.dat");
Creational patterns !0 of 205
JFrame frame = new JFrame("BuilderDemo - " + args[0]);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(target.get_result());
frame.pack();
frame.setVisible(true);
}
}
#nother Builder in 8aa 5,a*ple
/* "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
public void setDough(String dough) { this.dough = dough; }
public void setSauce(String sauce) { this.sauce = sauce; }
public void setTopping(String topping) { this.topping = topping; }
}
/* "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;
public Pizza getPizza() { return pizza; }
public void createNewPizzaProduct() { pizza = new Pizza(); }
public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}
/* "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("cross"); }
public void buildSauce() { pizza.setSauce("mild"); }
public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}
/* "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("pan baked"); }
public void buildSauce() { pizza.setSauce("hot"); }
public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}
/* "Director" */
class Waiter {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }
public void constructPizza() {
Creational patterns !1 of 205
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}
/* A customer ordering a pizza. */
class BuilderExample {
public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder( hawaiian_pizzabuilder );
waiter.constructPizza();
Pizza pizza = waiter.getPizza();
}
}
$actor% &ethod Design Pattern
Intent
&efine an interface for creating an ob8ect! but let subclasses decide +hich class to
instantiate. /actory Method lets a class defer instantiation to subclasses.
&efining a JvirtualK constructor.
*he ne+ operator considered harmful.
Proble*
A frame+ork needs to standardi@e the architectural model for a range of applications! but allo+
for individual applications to define their o+n domain ob8ects and provide for their instantiation.
Discussion
/actory Method is to creating ob8ects as *emplate Method is to implementing an algorithm. A
superclass specifies all standard and generic behavior Eusing pure virtual JplaceholdersK for
creation stepsG! and then delegates the creation details to subclasses that are supplied by the
client.
/actory Method makes a design more customi@able and only a little more complicated. 7ther
design patterns re=uire ne+ classes! +hereas /actory Method only re=uires a ne+ operation.
'eople often use /actory Method as the standard +ay to create ob8ectsI but it isnAt necessary if:
the class thatAs instantiated never changes! or instantiation takes place in an operation that
subclasses can easily override Esuch as an initiali@ation operationG.
/actory Method is similar to Abstract /actory but +ithout the emphasis on families.
/actory Methods are routinely specified by an architectural frame+ork! and then implemented by
the user of the frame+ork.
Creational patterns !2 of 205
Structure
*he implementation of /actory Method discussed in the Cang of /our Ebelo+G largely overlaps
+ith that of Abstract /actory. /or that reason! the presentation in this chapter focuses on the
approach that has become popular since.
An increasingly popular definition of factory method is: a static method of a class that returns an
ob8ect of that classA type. 6ut unlike a constructor! the actual ob8ect it returns might be an
instance of a subclass. %nlike a constructor! an e2isting ob8ect might be reused! instead of a ne+
ob8ect created. %nlike a constructor! factory methods can have different and more descriptive
names Ee.g.
Color.make_RGB_color(float red, float green, float blue) and
Color.make_HSB_color(float hue, float saturation, float brightness)
*he client is totally decoupled from the implementation details of derived classes. 'olymorphic
creation is no+ possible.
Creational patterns !! of 205
5,a*ple
*he /actory Method defines an interface for creating ob8ects! but lets subclasses decide +hich
classes to instantiate. -n8ection molding presses demonstrate this pattern. Manufacturers of
plastic toys process plastic molding po+der! and in8ect the plastic into molds of the desired
shapes. *he class of toy Ecar! action figure! etc.G is determined by the mold.
Chec0 list
$. -f you have an inheritance hierarchy that e2ercises polymorphism! consider adding a
polymorphic creation capability by defining a static factory method in the base class.
". &esign the arguments to the factory method. ?hat =ualities or characteristics are
necessary and sufficient to identify the correct derived class to instantiateO
). (onsider designing an internal Job8ect poolK that +ill allo+ ob8ects to be reused instead of
created from scratch.
9. (onsider making all constructors private or protected.
3ules of thu*b
Abstract /actory classes are often implemented +ith /actory Methods! but they can be
implemented using 'rototype.
/actory Methods are usually called +ithin *emplate Methods.
/actory Method: creation through inheritance. 'rototype: creation through delegation.
7ften! designs start out using /actory Method Eless complicated! more customi@able!
subclasses proliferateG and evolve to+ard Abstract /actory! 'rototype! or 6uilder Emore
fle2ible! more comple2G as the designer discovers +here more fle2ibility is needed.
'rototype doesnAt re=uire subclassing! but it does re=uire an -nitiali@e operation. /actory
Method re=uires subclassing! but doesnAt re=uire -nitiali@e.
*he advantage of a /actory Method is that it can return the same instance multiple times!
or can return a subclass rather than an ob8ect of that e2act type.
ome /actory Method advocates recommend that as a matter of language design Eor
failing that! as a matter of styleG absolutely all constructors should be private or protected.
-tAs no one elseAs business +hether a class manufactures a ne+ ob8ect or recycles an old
one.
*he ne+ operator considered harmful. *here is a difference bet+een re=uesting an ob8ect
and creating one. *he ne+ operator al+ays creates an ob8ect! and fails to encapsulate
ob8ect creation. A /actory Method enforces that encapsulation! and allo+s an ob8ect to be
re=uested +ithout ine2tricable coupling to the act of creation.
$actor% &ethod in C667 Before and after
Creational patterns !) of 205
Before
*he architect has done an admirable 8ob of decoupling the client from tooge concrete derived
classes! and! e2ercising polymorphism. 6ut there remains coupling +here instances are actually
created. -f +e design an Je2tra level of indirectionK Ea Jfactory methodKG and have clients use it
Einstead of Jne+KG! then the last bit of coupling goes a+ay. *he Jfactory methodK Eaka Jvirtual
constructorKG can be defined in the tooge base class! or! in a separate JfactoryK class. Note that
mainEG is no longer dependent on tooge derived classes.
class Stooge
{
public:
virtual void slap_stick() = 0;
};
class Larry: public Stooge
{
public:
void slap_stick()
{
cout << "Larry: poke eyes\n";
}
};
class Moe: public Stooge
{
public:
void slap_stick()
{
cout << "Moe: slap head\n";
}
};
class Curly: public Stooge
{
public:
void slap_stick()
{
cout << "Curly: suffer abuse\n";
}
};
int main()
{
vector<Stooge*> roles;
int choice;
while (true)
{
cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
cin >> choice;
if (choice == 0)
break;
else if (choice == 1)
roles.push_back(new Larry);
else if (choice == 2)
roles.push_back(new Moe);
else
roles.push_back(new Curly);
Creational patterns !5 of 205
}
for (int i = 0; i < roles.size(); i++)
roles[i]->slap_stick();
for (int i = 0; i < roles.size(); i++)
delete roles[i];
}
output:
Larry(1) Moe(2) Curly(3) Go(0): 2
Larry(1) Moe(2) Curly(3) Go(0): 1
Larry(1) Moe(2) Curly(3) Go(0): 3
Larry(1) Moe(2) Curly(3) Go(0): 0
Moe: slap head
Larry: poke eyes
Curly: suffer abuse
#fter
A factory method is a static method of a class that returns an ob8ect of that classA type. 6ut unlike
a constructor! the actual ob8ect it returns might be an instance of a subclass. Another advantage
of a factory method is that it can return e2isting instances multiple times.
class Stooge
{
public:
// Factory Method
static Stooge *make_stooge(int choice);
virtual void slap_stick() = 0;
};
int main()
{
vector<Stooge*> roles;
int choice;
while (true)
{
cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
cin >> choice;
if (choice == 0)
break;
roles.push_back(Stooge::make_stooge(choice));
}
for (int i = 0; i < roles.size(); i++)
roles[i]->slap_stick();
for (int i = 0; i < roles.size(); i++)
delete roles[i];
}
class Larry: public Stooge
{
public:
void slap_stick()
{
cout << "Larry: poke eyes\n";
}
Creational patterns !1 of 205
};
class Moe: public Stooge
{
public:
void slap_stick()
{
cout << "Moe: slap head\n";
}
};
class Curly: public Stooge
{
public:
void slap_stick()
{
cout << "Curly: suffer abuse\n";
}
};
Stooge *Stooge::make_stooge(int choice)
{
if (choice == 1)
return new Larry;
else if (choice == 2)
return new Moe;
else
return new Curly;
}
#nother $actor% &ethod C66 source code e,a*ple
&iscussion. /rame+orks are applications Eor subsystemsG +ith JholesK in them. 1ach frame+ork
specifies the infrastructure! superstructure! and flo+ of control for its JdomainK! and the client of
the frame+ork may: e2ercise the frame+orkAs default behavior Jas isK! e2tend selected pieces of
the frame+ork! or replace selected pieces.
*he /actory Method pattern addresses the notion of JcreationK in the conte2t of frame+orks. -n
this e2ample! the frame+ork kno+s ?D1N a ne+ document should be created! not ?DA* kind of
&ocument to create. *he JplaceholderK Application::(reate&ocumentEG has been declared by the
frame+ork! and the client is e2pected to Jfill in the blankK for his/her specific documentEsG. *hen!
+hen the client asks for Application::NewDocument()! the frame+ork +ill subse=uently call the
clientAs MyApplication::CreateDocument().
#include <iostream.h>
/* Abstract base class declared by framework */
class Document
{
public:
Document(char *fn)
{
strcpy(name, fn);
}
virtual void Open() = 0;
virtual void Close() = 0;
char *GetName()
{
Creational patterns !2 of 205
return name;
}
private:
char name[20];
};
/* Concrete derived class defined by client */
class MyDocument: public Document
{
public:
MyDocument(char *fn): Document(fn){}
void Open()
{
cout << " MyDocument: Open()" << endl;
}
void Close()
{
cout << " MyDocument: Close()" << endl;
}
};
/* Framework declaration */
class Application
{
public:
Application(): _index(0)
{
cout << "Application: ctor" << endl;
}
/* The client will call this "entry point" of the framework */
NewDocument(char *name)
{
cout << "Application: NewDocument()" << endl;
/* Framework calls the "hole" reserved for client customization */
_docs[_index] = CreateDocument(name);
_docs[_index++]->Open();
}
void OpenDocument(){}
void ReportDocs();
/* Framework declares a "hole" for the client to customize */
virtual Document *CreateDocument(char*) = 0;
private:
int _index;
/* Framework uses Document's base class */
Document *_docs[10];
};
void Application::ReportDocs()
{
cout << "Application: ReportDocs()" << endl;
for (int i = 0; i < _index; i++)
cout << " " << _docs[i]->GetName() << endl;
}
/* Customization of framework defined by client */
class MyApplication: public Application
Creational patterns !8 of 205
{
public:
MyApplication()
{
cout << "MyApplication: ctor" << endl;
}
/* Client defines Framework's "hole" */
Document *CreateDocument(char *fn)
{
cout << " MyApplication: CreateDocument()" << endl;
return new MyDocument(fn);
}
};
int main()
{
/* Client's customization of the Framework */
MyApplication myApp;
myApp.NewDocument("foo");
myApp.NewDocument("bar");
myApp.ReportDocs();
}
output:
Application: ctor
MyApplication: ctor
Application: NewDocument()
MyApplication: CreateDocument()
MyDocument: Open()
Application: NewDocument()
MyApplication: CreateDocument()
MyDocument: Open()
Application: ReportDocs()
foo
bar
$actor% &ethod in 8aa
public interface ImageReader {
public DecodedImage getDecodedImage();
}
public class GifReader implements ImageReader {
public GifReader( InputStream in ) {
// check that it's a gif, throw exception if it's not, then if it is decode it.
}
public DecodedImage getDecodedImage() {
return decodedImage;
}
}
public class JpegReader implements ImageReader {
//...
}
Creational patterns !4 of 205
'b(ect Pool Design Pattern
Intent
7b8ect pooling can offer a significant performance boostI it is most effective in situations +here
the cost of initiali@ing a class instance is high! the rate of instantiation of a class is high! and the
number of instantiations in use at any one time is lo+.
Proble*
7b8ect pools Eother+ise kno+n as resource poolsG are used to manage the ob8ect caching. A client
+ith access to a 7b8ect pool can avoid creating a ne+ 7b8ects by simply asking the pool for one
that has already been instantiated instead. Cenerally the pool +ill be a gro+ing pool! i.e. the pool
itself +ill create ne+ ob8ects if the pool is empty! or +e can have a pool! +hich restricts the
number of ob8ects created.
-t is desirable to keep all 5eusable ob8ects that are not currently in use in the same ob8ect pool so
that they can be managed by one coherent policy. *o achieve this! the 5eusable 'ool class is
designed to be a singleton class.
Discussion
*he 7b8ect 'ool lets others Jcheck outK ob8ects from its pool! +hen those ob8ects are no longer
needed by their processes! they are returned to the pool in order to be reused.
Do+ever! +e donAt +ant a process to have to +ait for a particular ob8ect to be released! so the
7b8ect 'ool also instantiates ne+ ob8ects as they are re=uired! but must also implement a facility
to clean up unused ob8ects periodically.
Structure
*he general idea for the (onnection 'ool pattern is that if instances of a class can be reused! you
avoid creating instances of the class by reusing them.
3eusable > -nstances of classes in this role collaborate +ith other ob8ects for a limited
amount of time! then they are no longer needed for that collaboration.
Client > -nstances of classes in this role use 5eusable ob8ects.
3eusablePool > -nstances of classes in this role manage 5eusable ob8ects for use by
(lient ob8ects.
%sually! it is desirable to keep all 5eusable ob8ects that are not currently in use in the same
ob8ect pool so that they can be managed by one coherent policy. *o achieve this! the 5eusable'ool
class is designed to be a singleton class. -ts constructorEsG are private! +hich forces other classes
to call its get-nstance method to get the one instance of the 5eusable'ool class.
A (lient ob8ect calls a 5eusable'ool ob8ectAs ac=uire5eusable method +hen it needs a 5eusable
ob8ect. A 5eusable'ool ob8ect maintains a collection of 5eusable ob8ects. -t uses the collection of
5eusable ob8ects to contain a pool of 5eusable ob8ects that are not currently in use.
Creational patterns )0 of 205
-f there are any 5eusable ob8ects in the pool +hen the ac=uire5eusable method is called! it
removes a 5eusable ob8ect from the pool and returns it. -f the pool is empty! then the
ac=uire5eusable method creates a 5eusable ob8ect if it can. -f the ac=uire5eusable method
cannot create a ne+ 5eusable ob8ect! then it +aits until a 5eusable ob8ect is returned to the
collection.
(lient ob8ects pass a 5eusable ob8ect to a 5eusable'ool ob8ectAs release5eusable method +hen
they are finished +ith the ob8ect. *he release5eusable method returns a 5eusable ob8ect to the
pool of 5eusable ob8ects that are not in use.
-n many applications of the 7b8ect 'ool pattern! there are reasons for limiting the total number of
5eusable ob8ects that may e2ist. -n such cases! the 5eusable'ool ob8ect that creates 5eusable
ob8ects is responsible for not creating more than a specified ma2imum number of 5eusable
ob8ects. -f 5eusable'ool ob8ects are responsible for limiting the number of ob8ects they +ill
create! then the 5eusable'ool class +ill have a method for specifying the ma2imum number of
ob8ects to be created. *hat method is indicated in the above diagram as setMa2'ooli@e.
5,a*ple
&o you like bo+lingO -f you do! you probably kno+ that you should change your shoes +hen you
getting the bo+ling club. hoe shelf is +onderful e2ample of 7b8ect 'ool. 7nce you +ant to play!
youAll get your pair Ea=uire5eusableG from it. After the game! youAll return shoes back to the shelf
Erelease5eusableG.
Chec0 list
$. (reate 7b8ect'ool class +ith private array of 7b8ects inside
". (reate ac=uare and release methods in 7b8ect'ool class
). Make sure that your 7b8ect'ool is ingleton
Creational patterns )1 of 205
3ules of thu*b
*he /actory Method pattern can be used to encapsulate the creation logic for ob8ects.
Do+ever! it does not manage them after their creation! the ob8ect pool pattern keeps track
of the ob8ects it creates.
7b8ect 'ools are usually implemented as ingletons.
'b(ect Pool in 8aa
// ObjectPool Class
public abstract class ObjectPool<T> {
private long expirationTime;
private Hashtable<T, Long> locked, unlocked;
public ObjectPool() {
expirationTime = 30000; // 30 seconds
locked = new Hashtable<T, Long>();
unlocked = new Hashtable<T, Long>();
}
protected abstract T create();
public abstract boolean validate(T o);
public abstract void expire(T o);
public synchronized T checkOut() {
long now = System.currentTimeMillis();
T t;
if (unlocked.size() > 0) {
Enumeration<T> e = unlocked.keys();
while (e.hasMoreElements()) {
t = e.nextElement();
if ((now - unlocked.get(t)) > expirationTime) {
// object has expired
unlocked.remove(t);
expire(t);
t = null;
} else {
if (validate(t)) {
unlocked.remove(t);
locked.put(t, now);
return (t);
} else {
// object failed validation
unlocked.remove(t);
expire(t);
t = null;
}
}
}
}
// no objects available, create a new one
Creational patterns )2 of 205
t = create();
locked.put(t, now);
return (t);
}
public synchronized void checkIn(T t) {
locked.remove(t);
unlocked.put(t, System.currentTimeMillis());
}
}
//The three remaining methods are abstract
//and therefore must be implemented by the subclass
public class JDBCConnectionPool extends ObjectPool<Connection> {
private String dsn, usr, pwd;
public JDBCConnectionPool(String driver, String dsn, String usr, String pwd) {
super();
try {
Class.forName(driver).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
this.dsn = dsn;
this.usr = usr;
this.pwd = pwd;
}
@Override
protected Connection create() {
try {
return (DriverManager.getConnection(dsn, usr, pwd));
} catch (SQLException e) {
e.printStackTrace();
return (null);
}
}
@Override
public void expire(Connection o) {
try {
((Connection) o).close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public boolean validate(Connection o) {
try {
return (!((Connection) o).isClosed());
} catch (SQLException e) {
e.printStackTrace();
return (false);
Creational patterns )! of 205
}
}
}
M&6((onnection'ool +ill allo+ the application to borro+ and return database connections:
public class Main {
public static void main(String args[]) {
// Do something...
...
// Create the ConnectionPool:
JDBCConnectionPool pool = new JDBCConnectionPool(
"org.hsqldb.jdbcDriver", "jdbc:hsqldb://localhost/mydb",
"sa", "secret");
// Get a connection:
Connection con = pool.checkOut();
// Use the connection
...
// Return the connection:
pool.checkIn(con);

}
}
Protot%pe Design Pattern
Intent
pecify the kinds of ob8ects to create using a prototypical instance! and create ne+ ob8ects
by copying this prototype.
(o>opt one instance of a class for use as a breeder of all future instances.
*he ne+ operator considered harmful.
Proble*
Application Jhard +iresK the class of ob8ect to create in each Jne+K e2pression.
Discussion
&eclare an abstract base class that specifies a pure virtual JcloneK method! and! maintains a
dictionary of all JcloneableK concrete derived classes. Any class that needs a Jpolymorphic
constructorK capability: derives itself from the abstract base class! registers its prototypical
instance! and implements the cloneEG operation.
*he client then! instead of +riting code that invokes the Jne+K operator on a hard>+ired class
name! calls a JcloneK operation on the abstract base class! supplying a string or enumerated data
type that designates the particular concrete derived class desired.
Creational patterns )) of 205
Structure
*he /actory kno+s ho+ to find the correct 'rototype! and each 'roduct kno+s ho+ to spa+n ne+
instances of itself.
5,a*ple
*he 'rototype pattern specifies the kind of ob8ects to create using a prototypical instance.
'rototypes of ne+ products are often built prior to full production! but in this e2ample! the
prototype is passive and does not participate in copying itself. *he mitotic division of a cell >
resulting in t+o identical cells > is an e2ample of a prototype that plays an active role in copying
itself and thus! demonstrates the 'rototype pattern. ?hen a cell splits! t+o cells of identical
genotvpe result. -n other +ords! the cell clones itself.
Chec0 list
$. Add a cloneEG method to the e2isting JproductK hierarchy.
". &esign a JregistryK that maintains a cache of prototypical ob8ects. *he registry could be
encapsulated in a ne+ /actory class! or in the base class of the JproductK hierarchy.
). &esign a factory method that: may Eor may notG accept arguments! finds the correct
prototype ob8ect! calls cloneEG on that ob8ect! and returns the result.
9. *he client replaces all references to the ne+ operator +ith calls to the factory method.
Creational patterns )5 of 205
3ules of thu*b
ometimes creational patterns are competitors: there are cases +hen either 'rototype or
Abstract /actory could be used properly. At other times they are complementory: Abstract
/actory might store a set of 'rototypes from +hich to clone and return product ob8ects.
Abstract /actory! 6uilder! and 'rototype can use ingleton in their implementations.
Abstract /actory classes are often implemented +ith /actory Methods! but they can be
implemented using 'rototype.
/actory Method: creation through inheritance. 'rotoype: creation through delegation.
7ften! designs start out using /actory Method Eless complicated! more customi@able!
subclasses proliferateG and evolve to+ard Abstract /actory! 'rotoype! or 6uilder Emore
fle2ible! more comple2G as the designer discovers +here more fle2ibility is needed.
'rototype doesnAt re=uire subclassing! but it does re=uire an Jinitiali@eK operation.
/actory Method re=uires subclassing! but doesnAt re=uire -nitiali@e.
&esigns that make heavy use of the (omposite and &ecorator patterns often can benefit
from 'rototype as +ell.
'rototype co>opts one instance of a class for use as a breeder of all future instances.
'rototypes are useful +hen ob8ect initiali@ation is e2pensive! and you anticipate fe+
variations on the initiali@ation parameters. -n this conte2t! 'rototype can avoid e2pensive
Jcreation from scratchK! and support cheap cloning of a pre>initiali@ed prototype.
'rototype is uni=ue among the other creational patterns in that it doesnAt re=uire a class P
only an ob8ect. 7b8ect>oriented languages like elf and 7mega that do a+ay +ith classes
completely rely on prototypes for creating ne+ ob8ects.
Protot%pe in C667 Before and after
Before
*he architect has done an admirable 8ob of decoupling the client from tooge concrete derived
classes! and! e2ercising polymorphism. 6ut there remains coupling +here instances are actually
created.
class Stooge
{
public:
virtual void slap_stick() = 0;
};
class Larry: public Stooge
{
public:
void slap_stick()
{
cout << "Larry: poke eyes\n";
}
};
class Moe: public Stooge
{
public:
void slap_stick()
Creational patterns )1 of 205
{
cout << "Moe: slap head\n";
}
};
class Curly: public Stooge
{
public:
void slap_stick()
{
cout << "Curly: suffer abuse\n";
}
};
int main()
{
vector roles;
int choice;
while (true)
{
cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
cin >> choice;
if (choice == 0)
break;
else if (choice == 1)
roles.push_back(new Larry);
else if (choice == 2)
roles.push_back(new Moe);
else
roles.push_back(new Curly);
}
for (int i = 0; i < roles.size(); i++)
roles[i]->slap_stick();
for (int i = 0; i < roles.size(); i++)
delete roles[i];
}
output:
Larry(1) Moe(2) Curly(3) Go(0): 2
Larry(1) Moe(2) Curly(3) Go(0): 1
Larry(1) Moe(2) Curly(3) Go(0): 3
Larry(1) Moe(2) Curly(3) Go(0): 0
Moe: slap head
Larry: poke eyes
Curly: suffer abuse
#fter
A cloneEG method has been added to the tooge hierarchy. 1ach derived class implements that
method by returning an instance of itself. A /actory class has been introduced that main> tains a
suite of JbreederK ob8ects Eaka proto> typesG! and kno+s ho+ to delegate to the correct prototype.
class Stooge {
public:
virtual Stooge* clone() = 0;
Creational patterns )2 of 205
virtual void slap_stick() = 0;
};
class Factory {
public:
static Stooge* make_stooge( int choice );
private:
static Stooge* s_prototypes[4];
};
int main() {
vector roles;
int choice;
while (true) {
cout << "Larry(1) Moe(2) Curly(3) Go(0): ";
cin >> choice;
if (choice == 0)
break;
roles.push_back(
Factory::make_stooge( choice ) );
}
for (int i=0; i < roles.size(); ++i)
roles[i]->slap_stick();
for (int i=0; i < roles.size(); ++i)
delete roles[i];
}
class Larry : public Stooge {
public:
Stooge* clone() { return new Larry; }
void slap_stick() {
cout << "Larry: poke eyes\n"; }
};
class Moe : public Stooge {
public:
Stooge* clone() { return new Moe; }
void slap_stick() {
cout << "Moe: slap head\n"; }
};
class Curly : public Stooge {
public:
Stooge* clone() { return new Curly; }
void slap_stick() {
cout << "Curly: suffer abuse\n"; }
};
Stooge* Factory::s_prototypes[] = {
0, new Larry, new Moe, new Curly
};
Stooge* Factory::make_stooge( int choice ) {
return s_prototypes[choice]->clone();
}
Creational patterns )8 of 205
Protot%pe in C66
Protot%pe design pattern de*o
&iscussion. -mage base class provides the mechanism for storing! finding! and cloning the
prototype for all derived classes. 1ach derived class specifies a private static data member +hose
initiali@ation JregistersK a prototype of itself +ith the base class. ?hen the client asks for a
JcloneK of a certain type! the base class finds the prototype and calls cloneEG on the correct
derived class.
#include <iostream.h>
enum imageType
{
LSAT, SPOT
};
class Image
{
public:
virtual void draw() = 0;
static Image *findAndClone(imageType);
protected:
virtual imageType returnType() = 0;
virtual Image *clone() = 0;
// As each subclass of Image is declared, it registers its prototype
static void addPrototype(Image *image)
{
_prototypes[_nextSlot++] = image;
}
private:
// addPrototype() saves each registered prototype here
static Image *_prototypes[10];
static int _nextSlot;
};
Image *Image::_prototypes[];
int Image::_nextSlot;
// Client calls this public static member function when it needs an instance
// of an Image subclass
Image *Image::findAndClone(imageType type)
{
for (int i = 0; i < _nextSlot; i++)
if (_prototypes[i]->returnType() == type)
return _prototypes[i]->clone();
}
class LandSatImage: public Image
{
public:
imageType returnType()
{
return LSAT;
}
void draw()
Creational patterns )4 of 205
{
cout << "LandSatImage::draw " << _id << endl;
}
// When clone() is called, call the one-argument ctor with a dummy arg
Image *clone()
{
return new LandSatImage(1);
}
protected:
// This is only called from clone()
LandSatImage(int dummy)
{
_id = _count++;
}
private:
// Mechanism for initializing an Image subclass - this causes the
// default ctor to be called, which registers the subclass's prototype
static LandSatImage _landSatImage;
// This is only called when the private static data member is inited
LandSatImage()
{
addPrototype(this);
}
// Nominal "state" per instance mechanism
int _id;
static int _count;
};
// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
// Initialize the "state" per instance mechanism
int LandSatImage::_count = 1;
class SpotImage: public Image
{
public:
imageType returnType()
{
return SPOT;
}
void draw()
{
cout << "SpotImage::draw " << _id << endl;
}
Image *clone()
{
return new SpotImage(1);
}
protected:
SpotImage(int dummy)
{
_id = _count++;
}
private:
SpotImage()
{
Creational patterns 50 of 205
addPrototype(this);
}
static SpotImage _spotImage;
int _id;
static int _count;
};
SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;
// Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};
int main()
{
Image *images[NUM_IMAGES];
// Given an image type, find the right prototype, and return a clone
for (int i = 0; i < NUM_IMAGES; i++)
images[i] = Image::findAndClone(input[i]);
// Demonstrate that correct image objects have been cloned
for (i = 0; i < NUM_IMAGES; i++)
images[i]->draw();
// Free the dynamic memory
for (i = 0; i < NUM_IMAGES; i++)
delete images[i];
}
output:
LandSatImage::draw 1
LandSatImage::draw 2
LandSatImage::draw 3
SpotImage::draw 1
LandSatImage::draw 4
SpotImage::draw 2
SpotImage::draw 3
LandSatImage::draw 5
Protot%pe in 8aa
Abstract /actory might store a set of 'rototypes from +hich to clone and return product ob8ects.
public class FactoryProto {
interface Xyz {
Xyz cloan();
}
static class Tom implements Xyz {
public Xyz cloan() {
Creational patterns 51 of 205
return new Tom();
}
public String toString() {
return "ttt";
}
}
static class Dick implements Xyz {
public Xyz cloan() {
return new Dick();
}
public String toString() {
return "ddd";
}
}
static class Harry implements Xyz {
public Xyz cloan() {
return new Harry();
}
public String toString() {
return "hhh";
}
}
static class Factory {
private static java.util.Map prototypes = new java.util.HashMap();
static {
prototypes.put( "tom", new Tom() );
prototypes.put( "dick", new Dick() );
prototypes.put( "harry", new Harry() );
}
public static Xyz makeObject( String s ) {
return ((Xyz)prototypes.get(s)).cloan();
}
}
public static void main( String[] args ) {
for (int i=0; i < args.length; i++) {
System.out.print( Factory.makeObject( args[i] ) + " " );
}
}
}
output:
D:\Java\patterns> java FactoryProto tom dick tom harry tom ttt ddd ttt hhh ttt
Protot%pe in 8aa 2
Protot%pe design pattern
$. (reate a JcontractK +ith cloneEG and getNameEG entries
". &esign a JregistryK that maintains a cache of prototypical ob8ects
Creational patterns 52 of 205
). 'opulate the registry +ith an initiali@e'rototypesEG function
9. *he registry has a findAnd(loneEG Jvirtual constructorK that can transform a tring into its
correct ob8ect Eit calls cloneEG +hich then calls Jne+KG
.. All classes relate themselves to the cloneEG contract
0. (lient uses the findAnd(loneEG virtual ctor instead of the Jne+K operator
interface Prototype {
Object clone();
String getName();
}
// 1. The clone() contract
interface Command {
void execute();
}
class PrototypesModule {
// 2. "registry" of prototypical objs
private static Prototype[] prototypes = new Prototype[9];
private static int total = 0;
// Adds a feature to the Prototype attribute of the PrototypesModule class
// obj The feature to be added to the Prototype attribute
public static void addPrototype( Prototype obj ) {
prototypes[total++] = obj;
}
public static Object findAndClone( String name ) {
// 4. The "virtual ctor"
for ( int i = 0; i < total; i++ ) {
if ( prototypes[i].getName().equals( name ) ) {
return prototypes[i].clone();
}
}
System.out.println( name + " not found" );
return null;
}
}
// 5. Sign-up for the clone() contract.
// Each class calls "new" on itself FOR the client.
class This implements Prototype, Command {
public Object clone() {
return new This();
}
public String getName() {
return "This";
}
public void execute() {
System.out.println( "This: execute" );
}
}
class That implements Prototype, Command {
public Object clone() {
Creational patterns 5! of 205
return new That();
}
public String getName() {
return "That";
}
public void execute() {
System.out.println( "That: execute" );
}
}
class TheOther implements Prototype, Command {
public Object clone() {
return new TheOther();
}
public String getName() {
return "TheOther";
}
public void execute() {
System.out.println( "TheOther: execute" );
}
}
public class PrototypeDemo {
// 3. Populate the "registry"
public static void initializePrototypes() {
PrototypesModule.addPrototype( new This() );
PrototypesModule.addPrototype( new That() );
PrototypesModule.addPrototype( new TheOther() );
}
public static void main( String[] args ) {
initializePrototypes();
Object[] objects = new Object[9];
int total = 0;
// 6. Client does not use "new"
for (int i=0; i < args.length; i++) {
objects[total] = PrototypesModule.findAndClone( args[i] );
if (objects[total] != null) total++;
}
for (int i=0; i < total; i++) {
((Command)objects[i]).execute();
}
}
}
C:> java PrototypeDemo Garbage This That Nothing TheOther
Garbage not found
Nothing not found
This: execute
That: execute
TheOther: execute
Singleton Design Pattern
Creational patterns 5) of 205
Intent
1nsure a class has only one instance! and provide a global point of access to it.
1ncapsulated J8ust>in>time initiali@ationK or Jinitiali@ation on first useK.
Proble*
Application needs one! and only one! instance of an ob8ect. Additionally! la@y initiali@ation and
global access are necessary.
Discussion
Make the class of the single instance ob8ect responsible for creation! initiali@ation! access! and
enforcement. &eclare the instance as a private static data member. 'rovide a public static
member function that encapsulates all initiali@ation code! and provides access to the instance.
*he client calls the accessor function Eusing the class name and scope resolution operatorG
+henever a reference to the single instance is re=uired.
ingleton should be considered only if all three of the follo+ing criteria are satisfied:
7+nership of the single instance cannot be reasonably assigned
,a@y initiali@ation is desirable
Clobal access is not other+ise provided for
-f o+nership of the single instance! +hen and ho+ initiali@ation occurs! and global access are not
issues! ingleton is not sufficiently interesting.
*he ingleton pattern can be e2tended to support access to an application>specific number of
instances.
*he Jstatic member function accessorK approach +ill not support subclassing of the ingleton
class. -f subclassing is desired! refer to the discussion in the book.
&eleting a ingleton class/instance is a non>trivial design problem.
Structure
Make the class of the single instance responsible for access and Jinitiali@ation on first useK. *he
single instance is a private static attribute. *he accessor function is a public static method.
5,a*ple
*he ingleton pattern ensures that a class has only one instance and provides a global point of
access to that instance. -t is named after the singleton set! +hich is defined to be a set containing
one element. *he office of the 'resident of the %nited tates is a ingleton. *he %nited tates
(onstitution specifies the means by +hich a president is elected! limits the term of office! and
defines the order of succession. As a result! there can be at most one active president at any
Creational patterns 55 of 205
given time. 5egardless of the personal identity of the active president! the title! J*he 'resident of
the %nited tatesK is a global point of access that identifies the person in the office.
Chec0 list
$. &efine a private static attribute in the Jsingle instanceK class.
". &efine a public static accessor function in the class.
). &o Jla@y initiali@ationK Ecreation on first useG in the accessor function.
9. &efine all constructors to be protected or private.
.. (lients may only use the accessor function to manipulate the ingleton.
3ules of thu*b
Abstract /actory! 6uilder! and 'rototype can use ingleton in their implementation.
/acade ob8ects are often ingletons because only one /acade ob8ect is re=uired.
tate ob8ects are often ingletons.
*he advantage of ingleton over global variables is that you are absolutely sure of the
number of instances +hen you use ingleton! and! you can change your mind and manage
any number of instances.
*he ingleton design pattern is one of the most inappropriately used patterns. ingletons
are intended to be used +hen a class must have e2actly one instance! no more! no less.
&esigners fre=uently use ingletons in a misguided attempt to replace global variables. A
ingleton is! for intents and purposes! a global variable. *he ingleton does not do a+ay
+ith the globalI it merely renames it.
?hen is ingleton unnecessaryO hort ans+er: most of the time. ,ong ans+er: +hen itAs
simpler to pass an ob8ect resource as a reference to the ob8ects that need it! rather than
letting ob8ects access the resource globally. *he real problem +ith ingletons is that they
give you such a good e2cuse not to think carefully about the appropriate visibility of an
ob8ect. /inding the right balance of e2posure and protection for an ob8ect is critical for
maintaining fle2ibility.
7ur group had a bad habit of using global data! so - did a study group on ingleton. *he
ne2t thing - kno+ ingletons appeared every+here and none of the problems related to
global data +ent a+ay. *he ans+er to the global data =uestion is not! JMake it a
ingleton.K *he ans+er is! J?hy in the hell are you using global dataOK (hanging the
name doesnAt change the problem. -n fact! it may make it +orse because it gives you the
opportunity to say! J?ell -Am not doing that! -Am doing thisK P even though this and that
are the same thing.
Creational patterns 51 of 205
Singleton in C667 Before and after
Before
A global variable is default initiali@ed > +hen it is declared > but it is not initiali@ed in earnest until
its first use. *his re=uires that the initiali@ation code be replicated throughout the application.
class GlobalClass
{
int m_value;
public:
GlobalClass(int v = 0)
{
m_value = v;
}
int get_value()
{
return m_value;
}
void set_value(int v)
{
m_value = v;
}
};
// Default initialization
GlobalClass *global_ptr = 0;
void foo(void)
{
// Initialization on first use
if (!global_ptr)
global_ptr = new GlobalClass;
global_ptr->set_value(1);
cout << "foo: global_ptr is " << global_ptr->get_value() << '\n';
}
void bar(void)
{
if (!global_ptr)
global_ptr = new GlobalClass;
global_ptr->set_value(2);
cout << "bar: global_ptr is " << global_ptr->get_value() << '\n';
}
int main()
{
if (!global_ptr)
global_ptr = new GlobalClass;
cout << "main: global_ptr is " << global_ptr->get_value() << '\n';
foo();
bar();
}
output:
main: global_ptr is 0
foo: global_ptr is 1
Creational patterns 52 of 205
bar: global_ptr is 2
#fter
Make the class responsible for its o+n global pointer and Binitiali@ation on first useB Eby using a
private static pointer and a public static accessor methodG. *he client uses only the public
accessor method.
class GlobalClass
{
int m_value;
static GlobalClass *s_instance;
GlobalClass(int v = 0)
{
m_value = v;
}
public:
int get_value()
{
return m_value;
}
void set_value(int v)
{
m_value = v;
}
static GlobalClass *instance()
{
if (!s_instance)
s_instance = new GlobalClass;
return s_instance;
}
};
// Allocating and initializing GlobalClass's
// static data member. The pointer is being
// allocated - not the object inself.
GlobalClass *GlobalClass::s_instance = 0;
void foo(void)
{
GlobalClass::instance()->set_value(1);
cout << "foo: global_ptr is " << GlobalClass::instance()->get_value() << '\n';
}
void bar(void)
{
GlobalClass::instance()->set_value(2);
cout << "bar: global_ptr is " << GlobalClass::instance()->get_value() << '\n';
}
int main()
{
cout << "main: global_ptr is " << GlobalClass::instance()->get_value() << '\n';
foo();
bar();
}
Creational patterns 58 of 205
output:
main: global_ptr is 0
foo: global_ptr is 1
bar: global_ptr is 2
Singleton in C66
Singleton design pattern
$. &efine a private static attribute in the Jsingle instanceK class
". &efine a public static accessor function in the class
). &o Jla@y initiali@ationK Ecreation on demandG in the accessor function
9. &efine all constructors to be protected or private
.. (lients may only use the accessor function to manipulate the ingleton
0. -nheritance can be supported! but static functions may not be overridden. *he base class
must be declared a friend of the derived class Ein order to access the protected
constructorG.
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
class Number
{
public:
// 2. Define a public static accessor func
static Number *instance();
static void setType(string t)
{
type = t;
delete inst;
inst = 0;
}
virtual void setValue(int in)
{
value = in;
}
virtual int getValue()
{
return value;
}
protected:
int value;
// 4. Define all ctors to be protected
Number()
{
cout << ":ctor: ";
}
// 1. Define a private static attribute
private:
static string type;
Creational patterns 54 of 205
static Number *inst;
};
string Number::type = "decimal";
Number *Number::inst = 0;
class Octal: public Number
{
// 6. Inheritance can be supported
public:
friend class Number;
void setValue(int in)
{
char buf[10];
sprintf(buf, "%o", in);
sscanf(buf, "%d", &value);
}
protected:
Octal(){}
};
Number *Number::instance()
{
if (!inst)
// 3. Do "lazy initialization" in the accessor function
if (type == "octal")
inst = new Octal();
else
inst = new Number();
return inst;
}
int main()
{
// Number myInstance; - error: cannot access protected constructor
// 5. Clients may only use the accessor function to manipulate the Singleton
Number::instance()->setValue(42);
cout << "value is " << Number::instance()->getValue() << endl;
Number::setType("octal");
Number::instance()->setValue(64);
cout << "value is " << Number::instance()->getValue() << endl;
}
output:
:ctor: value is 42
:ctor: value is 100
Singleton in 8aa
%niversity of Maryland (omputer cience researcher 6ill 'ugh has +ritten about the code issues
underlying the ingleton pattern +hen implemented in Mava. 'ughAs efforts on the J&ouble>
checked lockingK idiom led to changes in the Mava memory model in Mava . and to +hat is
generally regarded as the standard method to implement ingletons in Mava. *he techni=ue is
kno+n as the initiali@ation on demand holder idiom! is as la@y as possible! and +orks in all kno+n
versions of Mava. -t takes advantage of language guarantees about class initiali@ation! and +ill
therefore +ork correctly in all Mava>compliant compilers and virtual machines.
Creational patterns 10 of 205
*he inner class is referenced no earlier Eand therefore loaded no earlier by the class loaderG than
the moment that get-nstanceEG is called. *hus! this solution is thread>safe +ithout re=uiring
special language constructs Ei.e. volatile or synchroni@edG.
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}

/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
Structural patterns 11 of 205
Structural patterns
Introduction
-n oft+are 1ngineering! tructural &esign 'atterns are &esign 'atterns that ease the design by
identifying a simple +ay to reali@e relationships bet+een entities.
#dapter
Match interfaces of different classes
Bridge
eparates an ob8ectAs interface from its implementation
Co*posite
A tree structure of simple and composite ob8ects
Decorator
Add responsibilities to ob8ects dynamically
$acade
A single class that represents an entire subsystem
$l%+eight
A fine>grained instance used for efficient sharing
Priate Class Data
5estricts accessor/mutator access
Pro,%
An ob8ect representing another ob8ect
3ules of thu*b
$. Adapter makes things +ork after theyAre designedI 6ridge makes them +ork before they
are.
". 6ridge is designed up>front to let the abstraction and the implementation vary
independently. Adapter is retrofitted to make unrelated classes +ork together.
). Adapter provides a different interface to its sub8ect. 'ro2y provides the same interface.
&ecorator provides an enhanced interface.
9. Adapter changes an ob8ectAs interface! &ecorator enhances an ob8ectAs responsibilities.
&ecorator is thus more transparent to the client. As a conse=uence! &ecorator supports
recursive composition! +hich isnAt possible +ith pure Adapters.
.. (omposite and &ecorator have similar structure diagrams! reflecting the fact that both
rely on recursive composition to organi@e an open>ended number of ob8ects.
0. (omposite can be traversed +ith -terator. ;isitor can apply an operation over a
(omposite. (omposite could use (hain of responsibility to let components access global
properties through their parent. -t could also use &ecorator to override these properties
on parts of the composition. -t could use 7bserver to tie one ob8ect structure to another
and tate to let a component change its behavior as its state changes.
Structural patterns 12 of 205
3. (omposite can let you compose a Mediator out of smaller pieces through recursive
composition.
4. &ecorator lets you change the skin of an ob8ect. trategy lets you change the guts.
:. &ecorator is designed to let you add responsibilities to ob8ects +ithout subclassing.
(ompositeAs focus is not on embellishment but on representation. *hese intents are
distinct but complementary. (onse=uently! (omposite and &ecorator are often used in
concert.
$#. &ecorator and 'ro2y have different purposes but similar structures. 6oth describe ho+ to
provide a level of indirection to another ob8ect! and the implementations keep a reference
to the ob8ect to +hich they for+ard re=uests.
$$. /acade defines a ne+ interface! +hereas Adapter reuses an old interface. 5emember that
Adapter makes t+o e2isting interfaces +ork together as opposed to defining an entirely
ne+ one.
$". /acade ob8ects are often ingleton because only one /acade ob8ect is re=uired.
$). Mediator is similar to /acade in that it abstracts functionality of e2isting classes. Mediator
abstracts/centrali@es arbitrary communication bet+een colleague ob8ects! it routinely
Jadds valueK! and it is kno+n/referenced by the colleague ob8ects. -n contrast! /acade
defines a simpler interface to a subsystem! it doesnAt add ne+ functionality! and it is not
kno+n by the subsystem classes.
$9. Abstract /actory can be used as an alternative to /acade to hide platform>specific classes.
$.. ?hereas /ly+eight sho+s ho+ to make lots of little ob8ects! /acade sho+s ho+ to make a
single ob8ect represent an entire subsystem.
$0. /ly+eight is often combined +ith (omposite to implement shared leaf nodes.
$3. /ly+eight e2plains +hen and ho+ tate ob8ects can be shared.
#dapter Design Pattern
Intent
(onvert the interface of a class into another interface clients e2pect. Adapter lets classes
+ork together that couldnAt other+ise because of incompatible interfaces.
?rap an e2isting class +ith a ne+ interface.
-mpedance match an old component to a ne+ system
Proble*
An Joff the shelfK component offers compelling functionality that you +ould like to reuse! but its
Jvie+ of the +orldK is not compatible +ith the philosophy and architecture of the system
currently being developed.
Discussion
5euse has al+ays been painful and elusive. 7ne reason has been the tribulation of designing
something ne+! +hile reusing something old. *here is al+ays something not =uite right bet+een
the old and the ne+. -t may be physical dimensions or misalignment. -t may be timing or
synchroni@ation. -t may be unfortunate assumptions or competing standards.
-t is like the problem of inserting a ne+ three>prong electrical plug in an old t+o>prong +all
Structural patterns 1! of 205
outlet P some kind of adapter or intermediary is necessary.
Adapter is about creating an intermediary abstraction that translates! or maps! the old
component to the ne+ system. (lients call methods on the Adapter ob8ect +hich redirects them
into calls to the legacy component. *his strategy can be implemented either +ith inheritance or
+ith aggregation.
Adapter functions as a +rapper or modifier of an e2isting class. -t provides a different or
translated vie+ of that class.
Structure
6elo+! a legacy 5ectangle componentAs displayEG method e2pects to receive J2! y! +! hK
parameters. 6ut the client +ants to pass Jupper left 2 and yK and Jlo+er right 2 and yK. *his
incongruity can be reconciled by adding an additional level of indirection P i.e. an Adapter ob8ect.
*he Adapter could also be thought of as a J+rapperK.
Structural patterns 1) of 205
5,a*ple
*he Adapter pattern allo+s other+ise incompatible classes to +ork together by converting the
interface of one class into an interface e2pected by the clients. ocket +renches provide an
e2ample of the Adapter. A socket attaches to a ratchet! provided that the si@e of the drive is the
same. *ypical drive si@es in the %nited tates are $/"K and $/9K. 7bviously! a $/"K drive ratchet
+ill not fit into a $/9K drive socket unless an adapter is used. A $/"K to $/9K adapter has a $/"K
female connection to fit on the $/"K drive ratchet! and a $/9K male connection to fit in the $/9K
drive socket.
Chec0 list
$. -dentify the players: the componentEsG that +ant to be accommodated Ei.e. the clientG! and
the component that needs to adapt Ei.e. the adapteeG.
". -dentify the interface that the client re=uires.
). &esign a J+rapperK class that can Jimpedance matchK the adaptee to the client.
9. *he adapter/+rapper class Jhas aK instance of the adaptee class.
.. *he adapter/+rapper class JmapsK the client interface to the adaptee interface.
0. *he client uses Eis coupled toG the ne+ interface
3ules of thu*b
Adapter makes things +ork after theyAre designedI 6ridge makes them +ork before they
are.
6ridge is designed up>front to let the abstraction and the implementation vary
independently. Adapter is retrofitted to make unrelated classes +ork together.
Adapter provides a different interface to its sub8ect. 'ro2y provides the same interface.
&ecorator provides an enhanced interface.
Adapter is meant to change the interface of an e2isting ob8ect. &ecorator enhances
Structural patterns 15 of 205
another ob8ect +ithout changing its interface. &ecorator is thus more transparent to the
application than an adapter is. As a conse=uence! &ecorator supports recursive
composition! +hich isnAt possible +ith pure Adapters.
/acade defines a ne+ interface! +hereas Adapter reuses an old interface. 5emember that
Adapter makes t+o e2isting interfaces +ork together as opposed to defining an entirely
ne+ one.
#dapter in C66
#dapter design pattern de*o
&iscussion. ,egacy5ectangleAs interface is not compatible +ith the system that +ould like to
reuse it. An abstract base class is created that specifies the desired interface. An JadapterK class
is defined that publicly inherits the interface of the abstract class! and privately inherits the
implementation of the legacy component. *his adapter class JmapsK or Jimpedance matchesK the
ne+ interface to the old implementation.
#include <iostream.h>
typedef int Coordinate;
typedef int Dimension;
// Desired interface
class Rectangle
{
public:
virtual void draw() = 0;
};
// Legacy component
class LegacyRectangle
{
public:
LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2)
{
x1_ = x1;
y1_ = y1;
x2_ = x2;
y2_ = y2;
cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => ("
<< x2_ << "," << y2_ << ")" << endl;
}
void oldDraw()
{
cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_ <<
") => (" << x2_ << "," << y2_ << ")" << endl;
}
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
Structural patterns 11 of 205
};
// Adapter wrapper
class RectangleAdapter: public Rectangle, private LegacyRectangle
{
public:
RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h):
LegacyRectangle(x, y, x + w, y + h)
{
cout << "RectangleAdapter: create. (" << x << "," << y <&lt;
"), width = " &lt;&lt; w &lt;&lt; ", height = " &lt;&lt; h &lt;&lt; endl;
}
virtual void draw()
{
cout &lt;&lt; "RectangleAdapter: draw." &lt;&lt; endl;
oldDraw();
}
};
int main()
{
Rectangle *r = new RectangleAdapter(120, 200, 60, 40);
r->draw();
}
output:
LegacyRectangle: create. (120,200) => (180,240)
RectangleAdapter: create. (120,200), width = 60, height = 40
RectangleAdapter: draw.
LegacyRectangle: oldDraw. (120,200) => (180,240)
#dapter in C667 5,ternal Pol%*orphis*
$. pecify the ne+ desired interface
". &esign a J+rapperK class that can Jimpedance matchK the old to the ne+
). *he client uses Eis coupled toG the ne+ interface
9. *he adapter/+rapper JmapsK to the legacy implementation
#include "stdafx.h"
#include <iostream>
using namespace std;
class ExecuteInterface {
public:
// 1. Specify the new interface
virtual ~ExecuteInterface(){}
virtual void execute() = 0;
};
// 2. Design a "wrapper" or "adapter" class
template <class TYPE>
class ExecuteAdapter: public ExecuteInterface {
public:
ExecuteAdapter(TYPE *o, void(TYPE:: *m)()) {
Structural patterns 12 of 205
object = o;
method = m;
}
~ExecuteAdapter() {
delete object;
}
// 4. The adapter/wrapper "maps" the new to the legacy implementation
void execute() { /* the new */
(object->*method)();
}
private:
TYPE *object; // ptr-to-object attribute
void(TYPE:: *method)(); /* the old */ // ptr-to-member-function attribute
};
// The old: three totally incompatible classes
// no common base class,
class Fea {
public:
// no hope of polymorphism
~Fea() {
cout << "Fea::dtor" << endl;
}
void doThis() {
cout << "Fea::doThis()" << endl;
}
};
class Feye {
public:~Feye() {
cout << "Feye::dtor" << endl;
}
void doThat() {
cout << "Feye::doThat()" << endl;
}
};
class Pheau {
public:
~Pheau() {
cout << "Pheau::dtor" << endl;
}
void doTheOther() {
cout << "Pheau::doTheOther()" << endl;
}
};
/* the new is returned */
ExecuteInterface **initialize() {
ExecuteInterface **array = new ExecuteInterface *[3];
/* the old is below */
Structural patterns 18 of 205
array[0] = new ExecuteAdapter < Fea > (new Fea(), &Fea::doThis);
array[1] = new ExecuteAdapter < Feye > (new Feye(), &Feye::doThat);
array[2] = new ExecuteAdapter < Pheau > (new Pheau(), &Pheau::doTheOther);
return array;
}
int main() {
ExecuteInterface **objects = initialize();
for (int i = 0; i < 3; i++) {
objects[i]->execute();
}

// 3. Client uses the new (polymporphism)
for (i = 0; i < 3; i++) {
delete objects[i];
}
delete objects;
return 0;
}
output:
Fea::doThis()
Feye::doThat()
Pheau::doTheOther()
Fea::dtor
Feye::dtor
Pheau::dtor
#dapter in 8aa7 Before and after
Before
6ecause the interface bet+een ,ine and 5ectangle ob8ects is incapatible! the user has to recover
the type of each shape and manually supply the correct arguments.
class LegacyLine
{
public void draw(int x1, int y1, int x2, int y2)
{
System.out.println("line from (" + x1 + ',' + y1 + ") to (" + x2 + ','
+ y2 + ')');
}
}
class LegacyRectangle
{
public void draw(int x, int y, int w, int h)
{
System.out.println("rectangle at (" + x + ',' + y + ") with width " + w
+ " and height " + h);
}
}
public class AdapterDemo
Structural patterns 14 of 205
{
public static void main(String[] args)
{
Object[] shapes =
{
new LegacyLine(), new LegacyRectangle()
};
// A begin and end point from a graphical editor
int x1 = 10, y1 = 20;
int x2 = 30, y2 = 60;
for (int i = 0; i < shapes.length; ++i)
if (shapes[i].getClass().getName().equals("LegacyLine"))
((LegacyLine)shapes[i]).draw(x1, y1, x2, y2);
else if (shapes[i].getClass().getName().equals("LegacyRectangle"))
((LegacyRectangle)shapes[i]).draw(Math.min(x1, x2), Math.min(y1, y2)
, Math.abs(x2 - x1), Math.abs(y2 - y1));
}
}
line from (10,20) to (30,60)
rectangle at (10,20) with width 20 and height 40
#fter
*he AdapterAs Je2tra level of indirectionK takes care of mapping a user>friendly common interface
to legacy>specific peculiar interfaces.
class LegacyLine
{
public void draw(int x1, int y1, int x2, int y2)
{
System.out.println("line from (" + x1 + ',' + y1 + ") to (" + x2 + ','
+ y2 + ')');
}
}
class LegacyRectangle
{
public void draw(int x, int y, int w, int h)
{
System.out.println("rectangle at (" + x + ',' + y + ") with width " + w
+ " and height " + h);
}
}
interface Shape
{
void draw(int x1, int y1, int x2, int y2);
}
class Line implements Shape
{
private LegacyLine adaptee = new LegacyLine();
public void draw(int x1, int y1, int x2, int y2)
{
adaptee.draw(x1, y1, x2, y2);
}
}
Structural patterns 20 of 205
class Rectangle implements Shape
{
private LegacyRectangle adaptee = new LegacyRectangle();
public void draw(int x1, int y1, int x2, int y2)
{
adaptee.draw(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1),
Math.abs(y2 - y1));
}
}
public class AdapterDemo
{
public static void main(String[] args)
{
Shape[] shapes =
{
new Line(), new Rectangle()
};
// A begin and end point from a graphical editor
int x1 = 10, y1 = 20;
int x2 = 30, y2 = 60;
for (int i = 0; i < shapes.length; ++i)
shapes[i].draw(x1, y1, x2, y2);
}
}
output:
line from (10,20) to (30,60)
rectangle at (10,20) with width 20 and height 40
#dapter in 8aa
#nother #dapter source code e,a*ple
$. -dentify the desired interface.
". &esign a J+rapperK class that can Jimpedance matchK the old to the ne+.
). *he adapter/+rapper class Jhas aK instance of the legacy class.
9. *he adapter/+rapper class JmapsK Eor delegatesG to the legacy ob8ect.
.. *he client uses Eis coupled toG the ne+ interface.
/* The OLD */
class SquarePeg {
private double width;
public SquarePeg( double w ) { width = w; }
public double getWidth() { return width; }
public void setWidth( double w ) { width = w; }
}
/* The NEW */
class RoundHole {
Structural patterns 21 of 205
private int radius;
public RoundHole( int r ) {
radius = r;
System.out.println( "RoundHole: max SquarePeg is " + r * Math.sqrt(2) );
}
public int getRadius() { return radius; }
}
// Design a "wrapper" class that can "impedance match" the old to the new
class SquarePegAdapter {
// The adapter/wrapper class "has a" instance of the legacy class
private SquarePeg sp;
public SquarePegAdapter( double w ) { sp = new SquarePeg( w ); }
// Identify the desired interface
public void makeFit( RoundHole rh ) {
// The adapter/wrapper class delegates to the legacy object
double amount = sp.getWidth() - rh.getRadius() * Math.sqrt(2);
System.out.println( "reducing SquarePeg " + sp.getWidth() + " by " + ((amount
< 0) ? 0 : amount) + " amount" );
if (amount > 0) {
sp.setWidth( sp.getWidth() - amount );
System.out.println( " width is now " + sp.getWidth() );
}
}
}
class AdapterDemoSquarePeg {
public static void main( String[] args ) {
RoundHole rh = new RoundHole( 5 );
SquarePegAdapter spa;
for (int i=6; i < 10; i++) {
spa = new SquarePegAdapter( (double) i );
// The client uses (is coupled to) the new interface
spa.makeFit( rh );
}
}
}
output:
RoundHole: max SquarePeg is 7.0710678118
reducing SquarePeg 6.0 by 0.0 amount reducing SquarePeg 7.0 by 0.0 amount
reducing SquarePeg 8.0 by 0.9289321881345245 amount width is now 7.0710678118654755
reducing SquarePeg 9.0 by 1.9289321881345245 amount width is now 7.0710678118654755
Bridge Design Pattern
Intent
&ecouple an abstraction from its implementation so that the t+o can vary independently.
Structural patterns 22 of 205
'ublish interface in an inheritance hierarchy! and bury implementation in its o+n
inheritance hierarchy.
6eyond encapsulation! to insulation
Proble*
JDardening of the soft+are arteriesK has occurred by using subclassing of an abstract base class
to provide alternative implementations. *his locks in compile>time binding bet+een interface and
implementation. *he abstraction and implementation cannot be independently e2tended or
composed.
&otiation
(onsider the domain of Jthread schedulingK.
*here are t+o types of thread schedulers! and t+o types of operating systems or JplatformsK.
Civen this approach to speciali@ation! +e have to define a class for each permutation of these t+o
dimensions. -f +e add a ne+ platform Esay Q MavaAs ;irtual MachineG! +hat +ould our hierarchy
look likeO
?hat if +e had three kinds of thread schedulers! and four kinds of platformsO ?hat if +e had five
kinds of thread schedulers! and ten kinds of platformsO *he number of classes +e +ould have to
define is the product of the number of scheduling schemes and the number of platforms.
*he 6ridge design pattern proposes refactoring this e2ponentially e2plosive inheritance
hierarchy into t+o orthogonal hierarchies P one for platform>independent abstractions! and the
other for platform>dependent implementations.
Structural patterns 2! of 205
Discussion
&ecompose the componentAs interface and implementation into orthogonal class hierarchies. *he
interface class contains a pointer to the abstract implementation class. *his pointer is initiali@ed
+ith an instance of a concrete implementation class! but all subse=uent interaction from the
interface class to the implementation class is limited to the abstraction maintained in the
implementation base class. *he client interacts +ith the interface class! and it in turn JdelegatesK
all re=uests to the implementation class.
*he interface ob8ect is the JhandleK kno+n and used by the clientI +hile the implementation
ob8ect! or JbodyK! is safely encapsulated to ensure that it may continue to evolve! or be entirely
replaced Eor shared at run>time.
%se the 6ridge pattern +hen:
you +ant run>time binding of the implementation!
you have a proliferation of classes resulting from a coupled interface and numerous
implementations!
you +ant to share an implementation among multiple ob8ects!
you need to map orthogonal class hierarchies.
(onse=uences include:
decoupling the ob8ectAs interface!
improved e2tensibility Eyou can e2tend Ei.e. subclassG the abstraction and implementation
hierarchies independentlyG!
hiding details from clients.
6ridge is a synonym for the Jhandle/bodyK idiom. *his is a design mechanism that encapsulates
an implementation class inside of an interface class. *he former is the body! and the latter is the
handle. *he handle is vie+ed by the user as the actual class! but the +ork is done in the body.
J*he handle/body class idiom may be used to decompose a comple2 abstraction into smaller!
more manageable classes. *he idiom may reflect the sharing of a single resource by multiple
classes that control access to it Ee.g. reference countingG.K
Structure
*he (lient doesnAt +ant to deal +ith platform>dependent details. *he 6ridge pattern encapsulates
this comple2ity behind an abstraction J+rapperK.
6ridge emphasi@es identifying and decoupling JinterfaceK abstraction from JimplementationK
abstraction.
Structural patterns 2) of 205
5,a*ple
*he 6ridge pattern decouples an abstraction from its implementation! so that the t+o can vary
independently. A household s+itch controlling lights! ceiling fans! etc. is an e2ample of the
6ridge. *he purpose of the s+itch is to turn a device on or off. *he actual s+itch can be
implemented as a pull chain! simple t+o position s+itch! or a variety of dimmer s+itches.
Chec0 list
$. &ecide if t+o orthogonal dimensions e2ist in the domain. *hese independent concepts
could be: abstraction/platform! or domain/infrastructure! or front>end/back>end! or
interface/implementation.
". &esign the separation of concerns: +hat does the client +ant! and +hat do the platforms
provide.
). &esign a platform>oriented interface that is minimal! necessary! and sufficient. -ts goal is
to decouple the abstraction from the platform.
Structural patterns 25 of 205
9. &efine a derived class of that interface for each platform.
.. (reate the abstraction base class that Jhas aK platform ob8ect and delegates the platform>
oriented functionality to it.
0. &efine speciali@ations of the abstraction class if desired.
3ules of thu*b
Adapter makes things +ork after theyAre designedI 6ridge makes them +ork before they
are.
6ridge is designed up>front to let the abstraction and the implementation vary
independently. Adapter is retrofitted to make unrelated classes +ork together.
tate! trategy! 6ridge Eand to some degree AdapterG have similar solution structures.
*hey all share elements of the Jhandle/bodyK idiom. *hey differ in intent > that is! they
solve different problems.
*he structure of tate and 6ridge are identical Ee2cept that 6ridge admits hierarchies of
envelope classes! +hereas tate allo+s only oneG. *he t+o patterns use the same structure
to solve different problems: tate allo+s an ob8ectAs behavior to change along +ith its
state! +hile 6ridgeAs intent is to decouple an abstraction from its implementation so that
the t+o can vary independently.
-f interface classes delegate the creation of their implementation classes Einstead of
creating/coupling themselves directlyG! then the design usually uses the Abstract /actory
pattern to create the implementation ob8ects.
Bridge in C66
Bridge design pattern de*o
&iscussion. *he motivation is to decouple the *ime interface from the *ime implementation!
+hile still allo+ing the abstraction and the reali@ation to each be modelled +ith their o+n
inheritance hierarchy. *he implementation classes belo+ are straight>for+ard. *he interface
classes are a little more subtle. 5outinely! a 6ridge pattern interface hierarchy JhasaK
implementation class. Dere the interface base class JhasaK a pointer to the implementation base
class! and each class in the interface hierarchy is responsible for populating the base class
pointer +ith the correct concrete implementation class. *hen all re=uests from the client are
simply delegated by the interface class to the encapsulated implementation class.
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
class TimeImp {
public:
TimeImp(int hr, int min) {
hr_ = hr;
min_ = min;
}
virtual void tell() {
cout << "time is " << setw(2) << setfill(48) << hr_ << min_ << endl;
}
protected:
int hr_, min_;
};
Structural patterns 21 of 205
class CivilianTimeImp: public TimeImp {
public:
CivilianTimeImp(int hr, int min, int pm): TimeImp(hr, min) {
if (pm)
strcpy(whichM_, " PM");
else
strcpy(whichM_, " AM");
}
/* virtual */
void tell() {
cout << "time is " << hr_ << ":" << min_ << whichM_ << endl;
}
protected:
char whichM_[4];
};
class ZuluTimeImp: public TimeImp {
public:
ZuluTimeImp(int hr, int min, int zone): TimeImp(hr, min) {
if (zone == 5)
strcpy(zone_, " Eastern Standard Time");
else if (zone == 6)
strcpy(zone_, " Central Standard Time");
}
/* virtual */
void tell() {
cout << "time is " << setw(2) << setfill(48) << hr_ << min_ << zone_ <<
endl;
}
protected:
char zone_[30];
};
class Time {
public:
Time(){}
Time(int hr, int min) {
imp_ = new TimeImp(hr, min);
}
virtual void tell() {
imp_->tell();
}
protected:
TimeImp *imp_;
};
class CivilianTime: public Time {
public:
CivilianTime(int hr, int min, int pm) {
imp_ = new CivilianTimeImp(hr, min, pm);
}
};
Structural patterns 22 of 205
class ZuluTime: public Time {
public:
ZuluTime(int hr, int min, int zone) {
imp_ = new ZuluTimeImp(hr, min, zone);
}
};
int main() {
Time *times[3];
times[0] = new Time(14, 30);
times[1] = new CivilianTime(2, 30, 1);
times[2] = new ZuluTime(14, 30, 6);
for (int i = 0; i < 3; i++)
times[i]->tell();
}
output:
time is 1430
time is 2:30 PM
time is 1430 Central Standard Time
Bridge in 8aa 1
class Node {
public int value;
public Node prev, next;
public Node( int i ) { value = i; }
}
class StackArray {
private int[] items = new int[12];
private int total = -1;
public void push( int i ) { if ( ! isFull()) items[++total] = i; }
public boolean isEmpty() { return total == -1; }
public boolean isFull() { return total == 11; }
public int top() {
if (isEmpty()) return -1;
return items[total];
}
public int pop() {
if (isEmpty()) return -1;
return items[total--];
} }
class StackList {
private Node last;
public void push( int i ) {
if (last == null)
last = new Node( i );
else {
last.next = new Node( i );
last.next.prev = last;
last = last.next;
} }
public boolean isEmpty() { return last == null; }
Structural patterns 28 of 205
public boolean isFull() { return false; }
public int top() {
if (isEmpty()) return -1;
return last.value;
}
public int pop() {
if (isEmpty()) return -1;
int ret = last.value;
last = last.prev;
return ret;
} }
class StackFIFO extends StackArray {
private StackArray temp = new StackArray();
public int pop() {
while ( ! isEmpty())
temp.push( super.pop() );
int ret = temp.pop();
while ( ! temp.isEmpty())
push( temp.pop() );
return ret;
} }
class StackHanoi extends StackArray {
private int totalRejected = 0;
public int reportRejected() { return totalRejected; }
public void push( int in ) {
if ( ! isEmpty() && in > top())
totalRejected++;
else super.push( in );
} }
class BridgeDisc {
public static void main( String[] args ) {
StackArray[] stacks = { new StackArray(), new StackFIFO(), new
StackHanoi() };
StackList stack2 = new StackList();
for (int i=1, num; i < 15; i++) {
stacks[0].push( i );
stack2.push( i );
stacks[1].push( i );
}
java.util.Random rn = new java.util.Random();
for (int i=1, num; i < 15; i++)
stacks[2].push( rn.nextInt(20) );
while ( ! stacks[0].isEmpty())
System.out.print( stacks[0].pop() + " " );
System.out.println();
while ( ! stack2.isEmpty())
System.out.print( stack2.pop() + " " );
System.out.println();
while ( ! stacks[1].isEmpty())
System.out.print( stacks[1].pop() + " " );
System.out.println();
while ( ! stacks[2].isEmpty())
System.out.print( stacks[2].pop() + " " );
Structural patterns 24 of 205
System.out.println();
System.out.println( "total rejected is "
+ ((StackHanoi)stacks[2]).reportRejected() );
} }
output:
12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10 11 12
0 0 1 12 16 18
total rejected is 8
Bridge in 8aa 2
Bridge design pattern source code e,a*ple
$. (reate an implementation/body base class
". &erive the separate implementations from the common abstraction
). (reate an interface/+rapper class that JhasaK and delegates to the impl
9. 1mbellish the interface class +ith derived classes if desired
// Create an interface/wrapper class that "has a"
// implementation object and delegates all requests to it
class Stack {
protected StackImp imp;
public Stack( String s ) {
if (s.equals("java")) {
imp = new StackJava();
}
else {
imp = new StackMine();
}
}
public Stack() {
this( "java" );
}
public void push( int in ) {
imp.push( new Integer(in) );
}
public int pop() {
return ((Integer)imp.pop()).intValue();
}
public boolean isEmpty() {
return imp.empty();
}
}
// Embellish the interface class with derived classes if desired
class StackHanoi extends Stack {
private int totalRejected = 0;
public StackHanoi() { super( "java" ); }
public StackHanoi( String s ) { super( s ); }
Structural patterns 80 of 205
public int reportRejected() { return totalRejected; }
public void push( int in ) {
if ( ! imp.empty() && in > ((Integer)imp.peek()).intValue())
totalRejected++;
else
imp.push( new Integer(in) );
}
}
// Create an implementation/body base class
interface StackImp {
Object push( Object o );
Object peek();
boolean empty();
Object pop();
}
class StackJava extends java.util.Stack implements StackImp { }
// Derive the separate implementations from the common abstraction
class StackMine implements StackImp {
private Object[] items = new Object[20];
private int total = -1;
public Object push( Object o ) {
return items[++total] = o;
}
public Object peek() {
return items[total];
}
public Object pop() {
return items[total--];
}
public boolean empty() {
return total == -1;
}
}
class BridgeDemo {
public static void main(String[] args) {
Stack[] stacks = { new Stack("java"), new Stack("mine"),
new StackHanoi("java"), new StackHanoi("mine") };
for (int i=0, num; i < 20; i++) {
num = (int) (Math.random() * 1000) % 40;
for (int j=0; j < stacks.length; j++) stacks[j].push( num );
}
for (int i=0, num; i < stacks.length; i++) {
while ( ! stacks[i].isEmpty()) {
System.out.print( stacks[i].pop() + " " );
}
System.out.println();
}
System.out.println( "total rejected is " +
((StackHanoi)stacks[3]).reportRejected() );
}
}
Structural patterns 81 of 205
output:
30 3 6 10 0 14 23 39 2 5 30 20 13 31 9 4 30 11 15 36
30 3 6 10 0 14 23 39 2 5 30 20 13 31 9 4 30 11 15 36
0 2 4 11 15 36
0 2 4 11 15 36
total rejected is 14
Bridge in 8aa !
#nother Bridge design pattern e,a*ple
$. (reate an implementation/body abstraction
". &erive the separate implementations from the common abstraction
). (reate an interface/handle class that Jhas aK and delegates to the impl
9. 1mbellish the interface class +ith derived classes if desired
class Node {
public int value;
public Node prev, next;
public Node( int i ) { value = i; }
}
class Stack {
private StackImpl impl;
public Stack( String s ) {
if (s.equals("array")) impl = new StackArray();
else if (s.equals("list")) impl = new StackList();
else System.out.println( "Stack: unknown parameter" );
}
public Stack() { this( "array" ); }
public void push( int in ) { impl.push( in ); }
public int pop() { return impl.pop(); }
public int top() { return impl.top(); }
public boolean isEmpty() { return impl.isEmpty(); }
public boolean isFull() { return impl.isFull(); }
}
class StackHanoi extends Stack {
private int totalRejected = 0;
public StackHanoi() { super( "array" ); }
public StackHanoi( String s ) { super( s ); }
public int reportRejected() { return totalRejected; }
public void push( int in ) {
if ( ! isEmpty() && in > top()) {
totalRejected++;
}
else {
super.push( in );
}
}
}
Structural patterns 82 of 205
class StackFIFO extends Stack {
private StackImpl temp = new StackList();
public StackFIFO() {
super( "array" );
}
public StackFIFO( String s ) {
super( s );
}
public int pop() {
while ( ! isEmpty()) {
temp.push( super.pop() );
}
int ret = temp.pop();
while ( ! temp.isEmpty()) {
push( temp.pop() );
}
return ret;
}
}
interface StackImpl {
void push( int i );
int pop();
int top();
boolean isEmpty();
boolean isFull();
}
class StackArray implements StackImpl {
private int[] items = new int[12];
private int total = -1;
public void push( int i ) {
if ( ! isFull()) {
items[++total] = i;
}
public boolean isEmpty() {
return total == -1;
}
public boolean isFull() {
return total == 11;
}
public int top() {
if (isEmpty()) return -1;
return items[total];
}
public int pop() {
if (isEmpty()) return -1;
return items[total--];
}
}
}
class StackList implements StackImpl {
private Node last;
public void push( int i ) {
if (last == null)
Structural patterns 8! of 205
last = new Node( i );
else {
last.next = new Node( i );
last.next.prev = last;
last = last.next;
}
}
public boolean isEmpty() {
return last == null;
}
public boolean isFull() {
return false;
}
public int top() {
if (isEmpty()) return -1;
return last.value;
}
public int pop() {
if (isEmpty()) return -1;
int ret = last.value;
last = last.prev;
return ret;
}
}
class BridgeDisc {
public static void main( String[] args ) {
Stack[] stacks = { new Stack( "array" ), new Stack( "list" ),
new StackFIFO(), new StackHanoi() };
for (int i=1, num; i < 15; i++) {
for (int j=0; j < 3; j++) {
stacks[j].push( i );
}
}
java.util.Random rn = new java.util.Random();
for (int i=1, num; i < 15; i++) {
stacks[3].push( rn.nextInt(20) );
}
for (int i=0, num; i < stacks.length; i++) {
while ( ! stacks[i].isEmpty()) {
System.out.print( stacks[i].pop() + " " );
}
System.out.println();
}
System.out.println("total rejected is " +
((StackHanoi)stacks[3]).reportRejected() );
}
}
output:
12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10 11 12
0 0 1 12 16 18
total rejected is 8
Structural patterns 8) of 205
Co*posite Design Pattern
Intent
(ompose ob8ects into tree structures to represent +hole>part hierarchies. (omposite lets
clients treat individual ob8ects and compositions of ob8ects uniformly.
5ecursive composition
J&irectories contain entries! each of +hich could be a directory.K
$>to>many Jhas aK up the Jis aK hierarchy
Proble*
Application needs to manipulate a hierarchical collection of JprimitiveK and JcompositeK ob8ects.
'rocessing of a primitive ob8ect is handled one +ay! and processing of a composite ob8ect is
handled differently. Daving to =uery the JtypeK of each ob8ect before attempting to process it is
not desirable.
Discussion
&efine an abstract base class E(omponentG that specifies the behavior that needs to be e2ercised
uniformly across all primitive and composite ob8ects. ubclass the 'rimitive and (omposite
classes off of the (omponent class. 1ach (omposite ob8ect JcouplesK itself only to the abstract
type (omponent as it manages its JchildrenK.
%se this pattern +henever you have Jcomposites that contain components! each of +hich could
be a compositeK.
(hild management methods Re.g. add(hildEG! remove(hildEGS should normally be defined in the
(omposite class. %nfortunately! the desire to treat 'rimitives and (omposites uniformly re=uires
that these methods be moved to the abstract (omponent class. ee the J7pinionsK section belo+
for a discussion of JsafetyK versus JtransparencyK issues.
Structure
(omposites that contain (omponents! each of +hich could be a (omposite.
Menus that contain menu items! each of +hich could be a menu.
5o+>column C%- layout managers that contain +idgets! each of +hich could be a ro+>column
Structural patterns 85 of 205
C%- layout manager.
&irectories that contain files! each of +hich could be a directory.
(ontainers that contain 1lements! each of +hich could be a (ontainer.
5,a*ple
*he (omposite composes ob8ects into tree structures and lets clients treat individual ob8ects and
compositions uniformly. Although the e2ample is abstract! arithmetic e2pressions are
(omposites. An arithmetic e2pression consists of an operand! an operator EF > T /G! and another
operand. *he operand can be a number! or another arithmetic e2presssion. *hus! " F ) and E" F
)G F E9 T 0G are both valid e2pressions.
Chec0 list
$. 1nsure that your problem is about representing J+hole>partK hierarchical relationships.
". (onsider the heuristic! J(ontainers that contain containees! each of +hich could be a
container.K /or e2ample! JAssemblies that contain components! each of +hich could be an
assembly.K &ivide your domain concepts into container classes! and containee classes.
). (reate a Jlo+est common denominatorK interface that makes your containers and
containees interchangeable. -t should specify the behavior that needs to be e2ercised
uniformly across all containee and container ob8ects.
9. All container and containee classes declare an Jis aK relationship to the interface.
.. All container classes declare a one>to>many Jhas aK relationship to the interface.
0. (ontainer classes leverage polymorphism to delegate to their containee ob8ects.
3. (hild management methods Re.g. add(hildEG! remove(hildEGS should normally be defined in
the (omposite class. %nfortunately! the desire to treat ,eaf and (omposite ob8ects
uniformly may re=uire that these methods be promoted to the abstract (omponent class.
ee the Cang of /our for a discussion of these JsafetyK versus JtransparencyK trade>offs.
3ules of thu*b
(omposite and &ecorator have similar structure diagrams! reflecting the fact that both
rely on recursive composition to organi@e an open>ended number of ob8ects.
Structural patterns 81 of 205
(omposite can be traversed +ith -terator. ;isitor can apply an operation over a
(omposite. (omposite could use (hain of 5esponsibility to let components access global
properties through their parent. -t could also use &ecorator to override these properties
on parts of the composition. -t could use 7bserver to tie one ob8ect structure to another
and tate to let a component change its behavior as its state changes.
(omposite can let you compose a Mediator out of smaller pieces through recursive
composition.
&ecorator is designed to let you add responsibilities to ob8ects +ithout subclassing.
(ompositeAs focus is not on embellishment but on representation. *hese intents are
distinct but complementary. (onse=uently! (omposite and &ecorator are often used in
concert.
/ly+eight is often combined +ith (omposite to implement shared leaf nodes.
'pinions
*he +hole point of the (omposite pattern is that the (omposite can be treated atomically! 8ust
like a leaf. -f you +ant to provide an -terator protocol! fine! but - think that is outside the pattern
itself. At the heart of this pattern is the ability for a client to perform operations on an ob8ect
+ithout needing to kno+ that there are many ob8ects inside.
6eing able to treat a heterogeneous collection of ob8ects atomically Eor transparentlyG re=uires
that the Jchild managementK interface be defined at the root of the (omposite class hierarchy
Ethe abstract (omponent classG. Do+ever! this choice costs you safety! because clients may try to
do meaningless things like add and remove ob8ects from leaf ob8ects. 7n the other hand! if you
Jdesign for safetyK! the child management interface is declared in the (omposite class! and you
lose transparency because leaves and (omposites no+ have different interfaces.
malltalk implementations of the (omposite pattern usually do not have the interface for
managing the components in the (omponent interface! but in the (omposite interface. (FF
implementations tend to put it in the (omponent interface. *his is an e2tremely interesting fact!
and one that - often ponder. - can offer theories to e2plain it! but nobody kno+s for sure +hy it is
true.
My (omponent classes do not kno+ that (omposites e2ist. *hey provide no help for navigating
(omposites! nor any help for altering the contents of a (omposite. *his is because - +ould like
the base class Eand all its derivativesG to be reusable in conte2ts that do not re=uire (omposites.
?hen given a base class pointer! if - absolutely need to kno+ +hether or not it is a (omposite! -
+ill use dynamic_cast to figure this out. -n those cases +here dynamic_cast is too e2pensive! -
+ill use a ;isitor.
(ommon complaint: Jif - push the (omposite interface do+n into the (omposite class! ho+ am -
going to enumerate Ei.e. traverseG a comple2 structureOK My ans+er is that +hen - have behaviors
+hich apply to hierarchies like the one presented in the (omposite pattern! - typically use ;isitor!
so enumeration isnAt a problem > the ;isitor kno+s in each case! e2actly +hat kind of ob8ect itAs
dealing +ith. *he ;isitor doesnAt need every ob8ect to provide an enumeration interface.
(omposite doesnAt force you to treat all (omponents as (omposites. -t merely tells you to put all
operations that you +ant to treat JuniformlyK in the (omponent class. -f add! remove! and similar
operations cannot! or must not! be treated uniformly! then do not put them in the (omponent
base class. 5emember! by the +ay! that each patternAs structure diagram doesnAt define the
patternI it merely depicts +hat in our e2perience is a common reali@ation thereof. Must because
(ompositeAs structure diagram sho+s child management operations in the (omponent base class
doesnAt mean all implementations of the pattern must do the same.
Co*posite in C66 1
Structural patterns 82 of 205
Co*posite design pattern
$. -dentify the scalar/primitive classes and vector/container classes
". (reate an JinterfaceK Elo+est common denominatorG that can make all concrete classes
JinterchangeableK
). All concrete classes declare an Jis aK relationship to the interface
9. All JcontainerK classes couple themselves to the interface Erecursive composition!
(omposite Jhas aK set of children up the Jis aK hierarchyG
.. J(ontainerK classes use polymorphism as they delegate to their children
#include <iostream>
#include <vector>
using namespace std;
// 2. Create an "interface" (lowest common denominator)
class Component
{
public:
virtual void traverse() = 0;
};
class Leaf: public Component
{
// 1. Scalar class 3. "isa" relationship
int value;
public:
Leaf(int val)
{
value = val;
}
void traverse()
{
cout << value << ' ';
}
};
class Composite: public Component
{
// 1. Vector class 3. "isa" relationship
vector < Component * > children; // 4. "container" coupled to the interface
public:
// 4. "container" class coupled to the interface
void add(Component *ele)
{
children.push_back(ele);
}
void traverse()
{
for (int i = 0; i < children.size(); i++)
// 5. Use polymorphism to delegate to children
children[i]->traverse();
}
};
int main()
Structural patterns 88 of 205
{
Composite containers[4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 3; j++)
containers[i].add(new Leaf(i *3+j));
for (i = 1; i < 4; i++)
containers[0].add(&(containers[i]));
for (i = 0; i < 4; i++)
{
containers[i].traverse();
cout << endl;
}
}
output:
0 1 2 3 4 5 6 7 8 9 10 11
3 4 5
6 7 8
9 10 11
Co*posite in C66 2
Co*posite design pattern 9 *ultiple container classes
#include <iostream>
#include <vector>
using namespace std;
class Component
{
public:
virtual void traverse() = 0;
};
class Primitive: public Component
{
int value;
public:
Primitive(int val)
{
value = val;
}
void traverse()
{
cout << value << " ";
}
};
class Composite: public Component
{
vector < Component * > children;
Structural patterns 84 of 205
int value;
public:
Composite(int val)
{
value = val;
}
void add(Component *c)
{
children.push_back(c);
}
void traverse()
{
cout << value << " ";
for (int i = 0; i < children.size(); i++)
children[i]->traverse();
}
};
class Row: public Composite
{
public:
// Two different kinds of "con-
Row(int val): Composite(val){}
// tainer" classes. Most of the
void traverse()
{
// "meat" is in the Composite
cout << "Row"; // base class.
Composite::traverse();
}
};
class Column: public Composite
{
public:
Column(int val): Composite(val){}
void traverse()
{
cout << "Col";
Composite::traverse();
}
};
int main()
{
Row first(1); // Row1
Column second(2); // |
Column third(3); // +-- Col2
Row fourth(4); // | |
Row fifth(5); // | +-- 7
first.add(&second); // +-- Col3
first.add(&third); // | |
third.add(&fourth); // | +-- Row4
third.add(&fifth); // | | |
first.add(&Primitive(6)); // | | +-- 9
second.add(&Primitive(7)); // | +-- Row5
Structural patterns 40 of 205
third.add(&Primitive(8)); // | | |
fourth.add(&Primitive(9)); // | | +-- 10
fifth.add(&Primitive(10)); // | +-- 8
first.traverse(); // +-- 6
cout << '\n';
}
output:
Row1 Col2 7 Col3 Row4 9 Row5 10 8 6
Co*posite in 8aa7 Before and after
Before
class File
{
public File(String name)
{
m_name = name;
}
public void ls()
{
System.out.println(Composite.g_indent + m_name);
}
private String m_name;
}
class Directory
{
public Directory(String name)
{
m_name = name;
}
public void add(Object obj)
{
m_files.add(obj);
}
public void ls()
{
System.out.println(Composite.g_indent + m_name);
Composite.g_indent.append(" ");
for (int i = 0; i < m_files.size(); ++i)
{
Object obj = m_files.get(i);
// Recover the type of this object
if (obj.getClass().getName().equals("Directory"))
((Directory)obj).ls();
else
((File)obj).ls();
}
Composite.g_indent.setLength(CompositeDemo.g_indent.length() - 3);
}
private String m_name;
private ArrayList m_files = new ArrayList();
Structural patterns 41 of 205
}
publicclass CompositeDemo
{
public static StringBuffer g_indent = new StringBuffer();
public static void main(String[] args)
{
Directory one = new Directory("dir111"), two = new Directory("dir222"),
thr = new Directory("dir333");
File a = new File("a"), b = new File("b"), c = new File("c"), d = new
File("d"), e = new File("e");
one.add(a);
one.add(two);
one.add(b);
two.add(c);
two.add(d);
two.add(thr);
thr.add(e);
one.ls();
}
}
output:
dir111
a
dir222
c
d
dir333
e
b
#fter
// Define a "lowest common denominator"
interface AbstractFile
{
public void ls();
}
// File implements the "lowest common denominator"
class File implements AbstractFile
{
public File(String name)
{
m_name = name;
}
public void ls()
{
System.out.println(CompositeDemo.g_indent + m_name);
}
private String m_name;
}
Structural patterns 42 of 205
// Directory implements the "lowest common denominator"
class Directory implements AbstractFile
{
public Directory(String name)
{
m_name = name;
}
public void add(Object obj)
{
m_files.add(obj);
}
public void ls()
{
System.out.println(CompositeDemo.g_indent + m_name);
CompositeDemo.g_indent.append(" ");
for (int i = 0; i < m_files.size(); ++i)
{
// Leverage the "lowest common denominator"
AbstractFile obj = (AbstractFile)m_files.get(i);
obj.ls();
}
CompositeDemo.g_indent.setLength(CompositeDemo.g_indent.length() - 3);
}
private String m_name;
private ArrayList m_files = new ArrayList();
}
publicclass CompositeDemo
{
public static StringBuffer g_indent = new StringBuffer();
public static void main(String[] args)
{
Directory one = new Directory("dir111"), two = new Directory("dir222"),
thr = new Directory("dir333");
File a = new File("a"), b = new File("b"), c = new File("c"), d = new
File("d"), e = new File("e");
one.add(a);
one.add(two);
one.add(b);
two.add(c);
two.add(d);
two.add(thr);
thr.add(e);
one.ls();
}
}
Co*posite in 8aa7 "ser9configurable :ie+s: of a Co*posite
A second static attribute is used to remember the Jcurrent levelK of the traversal.
import java.util.List;
import java.util.ArrayList;
Structural patterns 4! of 205
abstract class Entity {
protected static StringBuffer indent = new StringBuffer();
protected static int level = 1;
public abstract void traverse( int[] levels );
protected boolean printThisLevel( int[] levels ) {
for (int i=0; i < levels.length; i++)
if (level == levels[i])
return true;
return false;
} }
class Product extends Entity {
private int value;
public Product( int val ) { value = val; }
public void traverse( int[] levels ) {
if (printThisLevel( levels ))
System.out.println( indent.toString() + value );
} }
class Box extends Entity {
private List children = new ArrayList();
private int value;
public Box( int val ) { value = val; }
public void add( Entity c ) { children.add( c ); }
public void traverse( int[] levels ) {
if (printThisLevel( levels )) {
System.out.println( indent.toString() + value );
indent.append( " " );
}
level++;
for (int i=0; i < children.size(); i++)
((Entity)children.get(i)).traverse( levels );
level--;
if (printThisLevel( levels ))
indent.setLength( indent.length() - 3 );
} }
public class CompositeLevelsAns {
public static void main( String[] args ) {
Box root = initialize();
int[] levels = new int[args.length];
for (int i=0; i < args.length; i++)
levels[i] = Integer.parseInt( args[i] );
root.traverse( levels );
}
private static Box initialize() {
Box[] nodes = new Box[7];
nodes[1] = new Box( 1 );
int[] s = { 1, 4, 7 };
for (int i=0; i < 3; i++) {
nodes[2] = new Box( 21+i );
nodes[1].add( nodes[2] );
int lev = 3;
for (int j=0; j < 4; j++) {
nodes[lev-1].add( new Product( lev*10 + s[i] ) );
Structural patterns 4) of 205
nodes[lev] = new Box( lev*10 + s[i]+1 );
nodes[lev-1].add( nodes[lev] );
nodes[lev-1].add( new Product( lev*10 + s[i]+2 ) );
lev++;
} }
return nodes[1];
} }
D:\java> java CompositeLevelsAns 2 4 6
21
41
42
61
62
63
43
22
44
45
64
65
66
46
23
47
48
67
68
69
49
D:\java> java CompositeLevelsAns 3 6
31
32
61
62
63
33
34
35
64
65
66
36
37
38
67
68
69
39
D:\java> java CompositeLevelsAns 1 2 3 4 5 6
1
21
31
32
41
42
51
52
61
62
63
53
Structural patterns 45 of 205
43
33
22
34
35
44
45
54
55
64
65
66
56
46
36
23
37
38
47
48
57
58
67
68
69
59
49
39
***************************************/
/or further e2amples follo+ these pages:
http://sourcemaking.com/design_patterns/composite/8ava/)
http://sourcemaking.com/design_patterns/composite/8ava/"
Decorator Design Pattern
Intent
Attach additional responsibilities to an ob8ect dynamically. &ecorators provide a fle2ible
alternative to subclassing for e2tending functionality.
(lient>specified embellishment of a core ob8ect by recursively +rapping it.
?rapping a gift! putting it in a bo2! and +rapping the bo2.
Proble*
Uou +ant to add behavior or state to individual ob8ects at run>time. -nheritance is not feasible
because it is static and applies to an entire class.
Discussion
uppose you are +orking on a user interface toolkit and you +ish to support adding borders and
scroll bars to +indo+s. Uou could define an inheritance hierarchy likeQ
Structural patterns 41 of 205
6ut the &ecorator pattern suggests giving the client the ability to specify +hatever combination
of JfeaturesK is desired.
Widget* aWidget = new BorderDecorator(
new HorizontalScrollBarDecorator(
new VerticalScrollBarDecorator(
new Window( 80, 24 ))));
aWidget->draw();
*his fle2ibility can be achieved +ith the follo+ing design
Another e2ample of cascading Eor chainingG features together to produce a custom ob8ect might
look like Q
Stream* aStream = new CompressingStream(
new ASCII7Stream(
new FileStream( "fileName.dat" )));
aStream->putString( "Hello world" );
*he solution to this class of problems involves encapsulating the original ob8ect inside an abstract
+rapper interface. 6oth the decorator ob8ects and the core ob8ect inherit from this abstract
interface. *he interface uses recursive composition to allo+ an unlimited number of decorator
JlayersK to be added to each core ob8ect.
Note that this pattern allo+s responsibilities to be added to an ob8ect! not methods to an ob8ectAs
interface. *he interface presented to the client must remain constant as successive layers are
specified.
Structural patterns 42 of 205
Also note that the core ob8ectAs identity has no+ been JhiddenK inside of a decorator ob8ect.
*rying to access the core ob8ect directly is no+ a problem.
Structure
*he client is al+ays interested in (ore/unctionality.do*hisEG. *he client may! or may not! be
interested in 7ptional7ne.do*hisEG and 7ptional*+o.do*hisEG. 1ach of these classes al+ays
delegate to the &ecorator base class! and that class al+ays delegates to the contained J+rappeeK
ob8ect.
5,a*ple
*he &ecorator attaches additional responsibilities to an ob8ect dynamically. *he ornaments that
are added to pine or fir trees are e2amples of &ecorators. ,ights! garland! candy canes! glass
ornaments! etc.! can be added to a tree to give it a festive look. *he ornaments do not change the
tree itself +hich is recogni@able as a (hristmas tree regardless of particular ornaments used. As
an e2ample of additional functionality! the addition of lights allo+s one to Jlight upK a (hristmas
tree.
Although paintings can be hung on a +all +ith or +ithout frames! frames are often added! and it
is the frame +hich is actually hung on the +all. 'rior to hanging! the paintings may be matted
and framed! +ith the painting! matting! and frame forming a single visual component.
Structural patterns 48 of 205
Chec0 list
$. 1nsure the conte2t is: a single core Eor non>optionalG component! several optional
embellishments or +rappers! and an interface that is common to all.
". (reate a J,o+est (ommon &enominatorK interface that makes all classes interchangeable.
). (reate a second level base class E&ecoratorG to support the optional +rapper classes.
9. *he (ore class and &ecorator class inherit from the ,(& interface.
.. *he &ecorator class declares a composition relationship to the ,(& interface! and this
data member is initiali@ed in its constructor.
0. *he &ecorator class delegates to the ,(& ob8ect.
3. &efine a &ecorator derived class for each optional embellishment.
4. &ecorator derived classes implement their +rapper functionality > and > delegate to the
&ecorator base class.
:. *he client configures the type and ordering of (ore and &ecorator ob8ects.
3ules of thu*b
Adapter provides a different interface to its sub8ect. 'ro2y provides the same interface.
&ecorator provides an enhanced interface.
Adapter changes an ob8ectAs interface! &ecorator enhances an ob8ectAs responsibilities.
&ecorator is thus more transparent to the client. As a conse=uence! &ecorator supports
recursive composition! +hich isnAt possible +ith pure Adapters.
(omposite and &ecorator have similar structure diagrams! reflecting the fact that both
rely on recursive composition to organi@e an open>ended number of ob8ects.
A &ecorator can be vie+ed as a degenerate (omposite +ith only one component.
Do+ever! a &ecorator adds additional responsibilities > it isnAt intended for ob8ect
aggregation.
&ecorator is designed to let you add responsibilities to ob8ects +ithout subclassing.
(ompositeAs focus is not on embellishment but on representation. *hese intents are
distinct but complementary. (onse=uently! (omposite and &ecorator are often used in
concert.
Structural patterns 44 of 205
(omposite could use (hain of 5esponsibility to let components access global properties
through their parent. -t could also use &ecorator to override these properties on parts of
the composition.
&ecorator and 'ro2y have different purposes but similar structures. 6oth describe ho+ to
provide a level of indirection to another ob8ect! and the implementations keep a reference
to the ob8ect to +hich they for+ard re=uests.
&ecorator lets you change the skin of an ob8ect. trategy lets you change the guts.
5,a*ple lin0s7
C66 e,a*ples
http://sourcemaking.com/design_patterns/decorator/cpp/$
http://sourcemaking.com/design_patterns/decorator/cpp/"
http://sourcemaking.com/design_patterns/decorator/cpp/)
8aa e,a*ples
http://sourcemaking.com/design_patterns/decorator/8ava/$
http://sourcemaking.com/design_patterns/decorator/8ava/"
http://sourcemaking.com/design_patterns/decorator/8ava/)
http://sourcemaking.com/design_patterns/decorator/8ava/9
$acade Design Pattern
Intent
'rovide a unified interface to a set of interfaces in a subsystem. /acade defines a higher>
level interface that makes the subsystem easier to use.
?rap a complicated subsystem +ith a simpler interface.
Proble*
A segment of the client community needs a simplified interface to the overall functionality of a
comple2 subsystem.
Discussion
/acade discusses encapsulating a comple2 subsystem +ithin a single interface ob8ect. *his
reduces the learning curve necessary to successfully leverage the subsystem. -t also promotes
decoupling the subsystem from its potentially many clients. 7n the other hand! if the /acade is
the only access point for the subsystem! it +ill limit the features and fle2ibility that Jpo+er usersK
may need.
*he /acade ob8ect should be a fairly simple advocate or facilitator. -t should not become an all>
kno+ing oracle or JgodK ob8ect.
Structure
Structural patterns 100 of 205
/acade takes a Jriddle +rapped in an enigma shrouded in mysteryK! and inter8ects a +rapper that
tames the amorphous and inscrutable mass of soft+are.
ubsystem7ne and ubsystem*hree do not interact +ith the internal components of
ubsystem*+o. *hey use the ubsystem*+o?rapper JfacadeK Ei.e. the higher level abstractionG.
5,a*ple
*he /acade defines a unified! higher level interface to a subsystem that makes it easier to use.
(onsumers encounter a /acade +hen ordering from a catalog. *he consumer calls one number
and speaks +ith a customer service representative. *he customer service representative acts as a
/acade! providing an interface to the order fulfillment department! the billing department! and
Structural patterns 101 of 205
the shipping department.
Chec0 list
$. -dentify a simpler! unified interface for the subsystem or component.
". &esign a V+rapperA class that encapsulates the subsystem.
). *he facade/+rapper captures the comple2ity and collaborations of the component! and
delegates to the appropriate methods.
9. *he client uses Eis coupled toG the /acade only.
.. (onsider +hether additional /acades +ould add value.
3ules of thu*b
/acade defines a ne+ interface! +hereas Adapter uses an old interface. 5emember that
Adapter makes t+o e2isting interfaces +ork together as opposed to defining an entirely
ne+ one.
?hereas /ly+eight sho+s ho+ to make lots of little ob8ects! /acade sho+s ho+ to make a
single ob8ect represent an entire subsystem.
Mediator is similar to /acade in that it abstracts functionality of e2isting classes. Mediator
abstracts/centrali@es arbitrary communications bet+een colleague ob8ects. -t routinely
Jadds valueK! and it is kno+n/referenced by the colleague ob8ects. -n contrast! /acade
defines a simpler interface to a subsystem! it doesnAt add ne+ functionality! and it is not
kno+n by the subsystem classes.
Abstract /actory can be used as an alternative to /acade to hide platform>specific classes.
/acade ob8ects are often ingletons because only one /acade ob8ect is re=uired.
Adapter and /acade are both +rappersI but they are different kinds of +rappers. *he
intent of /acade is to produce a simpler interface! and the intent of Adapter is to design to
an e2isting interface. ?hile /acade routinely +raps multiple ob8ects and Adapter +raps a
single ob8ectI /acade could front>end a single comple2 ob8ect and Adapter could +rap
several legacy ob8ects.
;uestion: o the +ay to tell the difference bet+een the Adapter pattern and the /acade pattern
is that the Adapter +raps one class and the /acade may represent many classesO
#ns+er: NoW 5emember! the Adapter pattern changes the interface of one or more classes into
one interface that a client is e2pecting. ?hile most te2tbook e2amples sho+ the adapter adapting
Structural patterns 102 of 205
one class! you may need to adapt many classes to provide the interface a client is coded to.
,ike+ise! a /acade may provide a simplified interface to a single class +ith a very comple2
interface. *he difference bet+een the t+o is not in terms of ho+ many classes they J+rapK! it is
in their intent.
$acade in C66
$acade design pattern de*o
&iscussion. tructuring a system into subsystems helps reduce comple2ity. A common design goal
is to minimi@e the communication and dependencies bet+een subsystems.
7ne +ay to achieve this goal is to introduce a JfacadeK ob8ect that provides a single! simplified
interface to the many! potentially comple2! individual interfaces +ithin the subsystem. -n this
e2ample! the JsubsystemK for responding to a net+orking service re=uest has been modeled! and
a facade E/acilities/acadeG interposed. *he facade JhidesK the t+isted and bi@arre choreography
necessary to satisfy even the most basic of re=uests. All the user of the facade ob8ect has to do is
make one or t+o phone calls a +eek for . months! and a completed service re=uest results.
#include <iostream.h>
class MisDepartment
{
public:
void submitNetworkRequest()
{
_state = 0;
}
bool checkOnStatus()
{
_state++;
if (_state == Complete)
return 1;
return 0;
}
private:
enum States
{
Received, DenyAllKnowledge, ReferClientToFacilities,
FacilitiesHasNotSentPaperwork, ElectricianIsNotDone,
ElectricianDidItWrong, DispatchTechnician, SignedOff, DoesNotWork,
FixElectriciansWiring, Complete
};
int _state;
};
class ElectricianUnion
{
public:
void submitNetworkRequest()
{
_state = 0;
}
bool checkOnStatus()
{
_state++;
Structural patterns 10! of 205
if (_state == Complete)
return 1;
return 0;
}
private:
enum States
{
Received, RejectTheForm, SizeTheJob, SmokeAndJokeBreak,
WaitForAuthorization, DoTheWrongJob, BlameTheEngineer, WaitToPunchOut,
DoHalfAJob, ComplainToEngineer, GetClarification, CompleteTheJob,
TurnInThePaperwork, Complete
};
int _state;
};
class FacilitiesDepartment
{
public:
void submitNetworkRequest()
{
_state = 0;
}
bool checkOnStatus()
{
_state++;
if (_state == Complete)
return 1;
return 0;
}
private:
enum States
{
Received, AssignToEngineer, EngineerResearches, RequestIsNotPossible,
EngineerLeavesCompany, AssignToNewEngineer, NewEngineerResearches,
ReassignEngineer, EngineerReturns, EngineerResearchesAgain,
EngineerFillsOutPaperWork, Complete
};
int _state;
};
class FacilitiesFacade
{
public:
FacilitiesFacade()
{
_count = 0;
}
void submitNetworkRequest()
{
_state = 0;
}
bool checkOnStatus()
{
_count++;
/* Job request has just been received */
if (_state == Received)
Structural patterns 10) of 205
{
_state++;
/* Forward the job request to the engineer */
_engineer.submitNetworkRequest();
cout << "submitted to Facilities - " << _count <<
" phone calls so far" << endl;
}
else if (_state == SubmitToEngineer)
{
/* If engineer is complete, forward to electrician */
if (_engineer.checkOnStatus())
{
_state++;
_electrician.submitNetworkRequest();
cout << "submitted to Electrician - " << _count <<
" phone calls so far" << endl;
}
}
else if (_state == SubmitToElectrician)
{
/* If electrician is complete, forward to technician */
if (_electrician.checkOnStatus())
{
_state++;
_technician.submitNetworkRequest();
cout << "submitted to MIS - " << _count <<
" phone calls so far" << endl;
}
}
else if (_state == SubmitToTechnician)
{
/* If technician is complete, job is done */
if (_technician.checkOnStatus())
return 1;
}
/* The job is not entirely complete */
return 0;
}
int getNumberOfCalls()
{
return _count;
}
private:
enum States
{
Received, SubmitToEngineer, SubmitToElectrician, SubmitToTechnician
};
int _state;
int _count;
FacilitiesDepartment _engineer;
ElectricianUnion _electrician;
MisDepartment _technician;
};
int main()
Structural patterns 105 of 205
{
FacilitiesFacade facilities;
facilities.submitNetworkRequest();
/* Keep checking until job is complete */
while (!facilities.checkOnStatus())
;
cout << "job completed after only " << facilities.getNumberOfCalls() <<
" phone calls" << endl;
}
output:
submitted to Facilities - 1 phone calls so far
submitted to Electrician - 12 phone calls so far
submitted to MIS - 25 phone calls so far
job completed after only 35 phone calls
$acade in 8aa
$acade design pattern
$. -dentify the desired unified interface for a set of subsystems
". &esign a J+rapperK class that can encapsulate the use of the subsystems
). *he client uses Eis coupled toG the /acade
9. *he facade/+rapper JmapsK to the A'-s of the subsystems
// 1. Subsystem
class PointCarte {
private double x, y;
public PointCarte( double xx, double yy ) {
x = xx;
y = yy;
}
public void move( int dx, int dy ) {
x += dx;
y += dy;
}
public String toString() {
return "(" + x + "," + y + ")";
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
// 1. Subsystem
class PointPolar {
private double radius, angle;
public PointPolar( double r, double a ) {
radius = r;
Structural patterns 101 of 205
angle = a;
}
public void rotate( int ang ) {
angle += ang % 360;
}
public String toString() {
return "[" + radius + "@" + angle + "]";
}
}
// 1. Desired interface: move(), rotate()
class Point {
private PointCarte pc; // 2. Design a "wrapper" class

public Point( double xx, double yy ) {
pc = new PointCarte( xx,yy );
}
public String toString() {
return pc.toString();
}
// 4. Wrapper maps
public void move( int dx, int dy ) {
pc.move( dx,dy );
}
public void rotate( int angle, Point o ) {
double x = pc.getX() - o.pc.getX();
double y = pc.getY() - o.pc.getY();
PointPolar pp = new PointPolar( Math.sqrt(x*x+y*y),
Math.atan2(y,x)*180/Math.PI );
// 4. Wrapper maps
pp.rotate( angle );
System.out.println( " PointPolar is " + pp );
String str = pp.toString(); int i = str.indexOf( '@' );
double r = Double.parseDouble( str.substring(1,i) );
double a = Double.parseDouble( str.substring(i+1,str.length()-1) );
pc = new PointCarte(r*Math.cos(a*Math.PI/180) + o.pc.getX(),
r*Math.sin(a*Math.PI/180) + o.pc.getY() );
}
}
class Line {
private Point o, e;
public Line( Point ori, Point end ) {
o = ori;
e = end;
}
public void move( int dx, int dy ) {
o.move( dx, dy );
e.move( dx, dy );
}
public void rotate( int angle ) {
e.rotate( angle, o );
}
public String toString() {
return "origin is " + o + ", end is " + e;
}
Structural patterns 102 of 205
}
class FacadeDemo {
public static void main( String[] args ) {
// 3. Client uses the Facade
Line line1 = new Line( new Point(2,4), new Point(5,7) );
line1.move(-2,-4);
System.out.println( "after move: " + line1 );
line1.rotate(45);
System.out.println( "after rotate: " + line1 );
Line line2 = new Line( new Point(2,1), new Point(2.866,1.5) );
line2.rotate(30);
System.out.println( "30 degrees to 60 degrees: " + line2 );
}
}
output:
after move: origin is (0.0,0.0), end is (3.0,3.0)
PointPolar is [4.242@90.0]
after rotate: origin is (0.0,0.0), end is (0.000,4.242)
PointPolar is [0.999@60.0] 30 degrees to 60 degrees: origin is (2.0,1.0), end is
(2.499,1.866)
$l%+eight Design Pattern
Intent
%se sharing to support large numbers of fine>grained ob8ects efficiently.
*he Motif C%- strategy of replacing heavy>+eight +idgets +ith light>+eight gadgets.
Proble*
&esigning ob8ects do+n to the lo+est levels of system JgranularityK provides optimal fle2ibility!
but can be unacceptably e2pensive in terms of performance and memory usage.
Discussion
*he /ly+eight pattern describes ho+ to share ob8ects to allo+ their use at fine granularities
+ithout prohibitive cost. 1ach Jfly+eightK ob8ect is divided into t+o pieces: the state>dependent
Ee2trinsicG part! and the state>independent EintrinsicG part. -ntrinsic state is stored EsharedG in the
/ly+eight ob8ect. 12trinsic state is stored or computed by client ob8ects! and passed to the
/ly+eight +hen its operations are invoked.
An illustration of this approach +ould be Motif +idgets that have been re>engineered as light>
+eight gadgets. ?hereas +idgets are JintelligentK enough to stand on their o+nI gadgets e2ist in
a dependent relationship +ith their parent layout manager +idget. 1ach layout manager provides
conte2t>dependent event handling! real estate management! and resource services to its
fly+eight gadgets! and each gadget is only responsible for conte2t>independent state and
behavior.
Structure
/ly+eights are stored in a /actoryAs repository. *he client restrains herself from creating
Structural patterns 108 of 205
/ly+eights directly! and re=uests them from the /actory. 1ach /ly+eight cannot stand on its o+n.
Any attributes that +ould make sharing impossible must be supplied by the client +henever a
re=uest is made of the /ly+eight. -f the conte2t lends itself to Jeconomy of scaleK Ei.e. the client
can easily compute or look>up the necessary attributesG! then the /ly+eight pattern offers
appropriate leverage.
*he Ant! ,ocust! and (ockroach classes can be Jlight>+eightK because their instance>specific
state has been de>encapsulated! or e2ternali@ed! and must be supplied by the client.
5,a*ple
*he /ly+eight uses sharing to support large numbers of ob8ects efficiently. *he public s+itched
telephone net+ork is an e2ample of a /ly+eight. *here are several resources such as dial tone
generators! ringing generators! and digit receivers that must be shared bet+een all subscribers.
A subscriber is una+are of ho+ many resources are in the pool +hen he or she lifts the handset
to make a call. All that matters to subscribers is that a dial tone is provided! digits are received!
and the call is completed.
Structural patterns 104 of 205
Chec0 list
$. 1nsure that ob8ect overhead is an issue needing attention! and! the client of the class is
able and +illing to absorb responsibility realignment.
". &ivide the target classAs state into: shareable EintrinsicG state! and non>shareable
Ee2trinsicG state.
). 5emove the non>shareable state from the class attributes! and add it the calling argument
list of affected methods.
9. (reate a /actory that can cache and reuse e2isting class instances.
.. *he client must use the /actory instead of the ne+ operator to re=uest ob8ects.
0. *he client Eor a third partyG must look>up or compute the non>shareable state! and supply
that state to class methods.
3ules of thu*b
?hereas /ly+eight sho+s ho+ to make lots of little ob8ects! /acade sho+s ho+ to make a
single ob8ect represent an entire subsystem.
/ly+eight is often combined +ith (omposite to implement shared leaf nodes.
*erminal symbols +ithin -nterpreterAs abstract synta2 tree can be shared +ith /ly+eight.
/ly+eight e2plains +hen and ho+ tate ob8ects can be shared.
$l%+eight in C667 Before and after
Before
*rying to use ob8ects at very lo+ levels of granularity is nice! but the overhead may be
prohibitive. /ly+eight suggests removing the non>shareable state from the class! and having the
client supply it +hen methods are called. *his places more responsibility on the client! but!
considerably fe+er instances of the /ly+eight class are no+ created. haring of these instances
is facilitated by introducing a /actory class that maintains a JcacheK of e2isting /ly+eights.
-n this e2ample! the JNK state is considered shareable E+ithin each ro+ any+aysG! and the JUK
state has been e2ternali@ed Eit is supplied by the client +hen reportEG is calledG.
class Gazillion
Structural patterns 110 of 205
{
public:
Gazillion()
{
m_value_one = s_num / Y;
m_value_two = s_num % Y;
++s_num;
}
void report()
{
cout << m_value_one << m_value_two << ' ';
}
static int X, Y;
private:
int m_value_one;
int m_value_two;
static int s_num;
};
int Gazillion::X = 6, Gazillion::Y = 10, Gazillion::s_num = 0;
int main()
{
Gazillion matrix[Gazillion::X][Gazillion::Y];
for (int i = 0; i < Gazillion::X; ++i)
{
for (int j = 0; j < Gazillion::Y; ++j)
matrix[i][j].report();
cout << '\n';
}
}
output:
00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
#fter
class Gazillion
{
public:
Gazillion(int value_one)
{
m_value_one = value_one;
cout << "ctor: " << m_value_one << '\n';
}
~Gazillion()
{
cout << m_value_one << ' ';
}
void report(int value_two)
{
Structural patterns 111 of 205
cout << m_value_one << value_two << ' ';
}
private:
int m_value_one;
};
class Factory
{
public:
static Gazillion *get_fly(int in)
{
if (!s_pool[in])
s_pool[in] = new Gazillion(in);
return s_pool[in];
}
static void clean_up()
{
cout << "dtors: ";
for (int i = 0; i < X; ++i)
if (s_pool[i])
delete s_pool[i];
cout << '\n';
}
static int X, Y;
private:
static Gazillion *s_pool[];
};
int Factory::X = 6, Factory::Y = 10;
Gazillion *Factory::s_pool[] =
{
0, 0, 0, 0, 0, 0
};
int main()
{
for (int i = 0; i < Factory::X; ++i)
{
for (int j = 0; j < Factory::Y; ++j)
Factory::get_fly(i)->report(j);
cout << '\n';
}
Factory::clean_up();
}
output:
ctor: 0
00 01 02 03 04 05 06 07 08 09
ctor: 1
10 11 12 13 14 15 16 17 18 19
ctor: 2
20 21 22 23 24 25 26 27 28 29
ctor: 3
30 31 32 33 34 35 36 37 38 39
ctor: 4
40 41 42 43 44 45 46 47 48 49
Structural patterns 112 of 205
ctor: 5
50 51 52 53 54 55 56 57 58 59
dtors: 0 1 2 3 4 5
$l%+eight in C66
$l%+eight design pattern de*o
&iscussion. /ly+eight describes ho+ to share ob8ects! so that their use at fine granularities is not
cost prohibitive. A key concept is the distinction bet+een JintrinsicK and Je2trinsicK state.
-ntrinsic state consists of information that is independent of the fly+eightAs conte2t > information
that is sharable Ei.e. each -conAs name! +idth! and heightG.
-t is stored in the fly+eight Ei.e. the -con classG. 12trinsic state cannot be shared! it depends on
and varies +ith the ly+eightAs conte2t Ei.e. the 2!y position that each -con instanceAs upper left
corner +ill be dra+n atG. 12trinsic state is stored or computed by the client and is passed to the
fly+eight +hen an operation is invoked. (lients should not instantiate /ly+eights directly! they
should obtain them e2clusively from a /ly+eight/actory ob8ect to ensure they are shared
properly.
#include <iostream.h>
#include <string.h>
class Icon
{
public:
Icon(char *fileName)
{
strcpy(_name, fileName);
if (!strcmp(fileName, "go"))
{
_width = 20;
_height = 20;
}
if (!strcmp(fileName, "stop"))
{
_width = 40;
_height = 40;
}
if (!strcmp(fileName, "select"))
{
_width = 60;
_height = 60;
}
if (!strcmp(fileName, "undo"))
{
_width = 30;
_height = 30;
}
}
const char *getName()
{
return _name;
}
Structural patterns 11! of 205
draw(int x, int y)
{
cout << " drawing " << _name << ": upper left (" << x << "," << y <<
") - lower right (" << x + _width << "," << y + _height << ")" <<
endl;
}
private:
char _name[20];
int _width;
int _height;
};
class FlyweightFactory
{
public:
static Icon *getIcon(char *name)
{
for (int i = 0; i < _numIcons; i++)
if (!strcmp(name, _icons[i]->getName()))
return _icons[i];
_icons[_numIcons] = new Icon(name);
return _icons[_numIcons++];
}
static void reportTheIcons()
{
cout << "Active Flyweights: ";
for (int i = 0; i < _numIcons; i++)
cout << _icons[i]->getName() << " ";
cout << endl;
}
private:
enum
{
MAX_ICONS = 5
};
static int _numIcons;
static Icon *_icons[MAX_ICONS];
};
int FlyweightFactory::_numIcons = 0;
Icon *FlyweightFactory::_icons[];
class DialogBox
{
public:
DialogBox(int x, int y, int incr): _iconsOriginX(x), _iconsOriginY(y),
_iconsXIncrement(incr){}
virtual void draw() = 0;
protected:
Icon *_icons[3];
int _iconsOriginX;
int _iconsOriginY;
int _iconsXIncrement;
};
class FileSelection: public DialogBox
Structural patterns 11) of 205
{
public:
FileSelection(Icon *first, Icon *second, Icon *third): DialogBox(100, 100,
100)
{
_icons[0] = first;
_icons[1] = second;
_icons[2] = third;
}
void draw()
{
cout << "drawing FileSelection:" << endl;
for (int i = 0; i < 3; i++)
_icons[i]->draw(_iconsOriginX + (i *_iconsXIncrement), _iconsOriginY);
}
};
class CommitTransaction: public DialogBox
{
public:
CommitTransaction(Icon *first, Icon *second, Icon *third): DialogBox(150,
150, 150)
{
_icons[0] = first;
_icons[1] = second;
_icons[2] = third;
}
void draw()
{
cout << "drawing CommitTransaction:" << endl;
for (int i = 0; i < 3; i++)
_icons[i]->draw(_iconsOriginX + (i *_iconsXIncrement), _iconsOriginY);
}
};
int main()
{
DialogBox *dialogs[2];
dialogs[0] = new FileSelection(FlyweightFactory::getIcon("go"),
FlyweightFactory::getIcon("stop"), FlyweightFactory::getIcon("select"));
dialogs[1] = new CommitTransaction(FlyweightFactory::getIcon("select"),
FlyweightFactory::getIcon("stop"), FlyweightFactory::getIcon("undo"));
for (int i = 0; i < 2; i++)
dialogs[i]->draw();
FlyweightFactory::reportTheIcons();
}
output:
drawing FileSelection:
drawing go: upper left (100,100) - lower right (120,120)
drawing stop: upper left (200,100) - lower right (240,140)
drawing select: upper left (300,100) - lower right (360,160)
drawing CommitTransaction:
drawing select: upper left (150,150) - lower right (210,210)
drawing stop: upper left (300,150) - lower right (340,190)
Structural patterns 115 of 205
drawing undo: upper left (450,150) - lower right (480,180)
Active Flyweights: go stop select undo
$l%+eight in 8aa
$l%+eight design pattern
&iscussion. *rying to use ob8ects at very lo+ levels of granularity is nice! but the overhead may
be prohibitive. /ly+eight suggests removing the non>shareable state from the class! and having
the client supply it +hen methods are called. *his places more responsibility on the client! but!
considerably fe+er instances of the /ly+eight class are no+ created. haring of these instances
is facilitated by introducing a /actory class that maintains a JcacheK of e2isting /ly+eights.
class Gazillion {
private static int num = 0;
private int row, col;
public Gazillion( int maxPerRow ) {
row = num / maxPerRow;
col = num % maxPerRow;
num++;
}
void report() {
System.out.print( " " + row + col );
} }
public class FlyweightDemo {
public static final int ROWS = 6, COLS = 10;
public static void main( String[] args ) {
Gazillion[][] matrix = new Gazillion[ROWS][COLS];
for (int i=0; i < ROWS; i++)
for (int j=0; j < COLS; j++)
matrix[i][j] = new Gazillion( COLS );
for (int i=0; i < ROWS; i++) {
for (int j=0; j < COLS; j++)
matrix[i][j].report();
System.out.println();
} } }
output:
00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
-n this refactoring! the Jro+K state is considered shareable E+ithin each ro+ any+aysG! and the
JcolK state has been e2ternali@ed Eit is supplied by the client +hen reportEG is calledG.
class Gazillion {
private int row;
public Gazillion( int theRow ) {
row = theRow;
System.out.println( "ctor: " + row );
}
Structural patterns 111 of 205
void report( int theCol ) {
System.out.print( " " + row + theCol );
} }
class Factory {
private Gazillion[] pool;
public Factory( int maxRows ) {
pool = new Gazillion[maxRows];
}
public Gazillion getFlyweight( int theRow ) {
if (pool[theRow] == null)
pool[theRow] = new Gazillion( theRow );
return pool[theRow];
} }
public class FlyweightDemo {
public static final int ROWS = 6, COLS = 10;
public static void main( String[] args ) {
Factory theFactory = new Factory( ROWS );
for (int i=0; i < ROWS; i++) {
for (int j=0; j < COLS; j++)
theFactory.getFlyweight( i ).report( j );
System.out.println();
} } }
output:
ctor: 0
00 01 02 03 04 05 06 07 08 09
ctor: 1
10 11 12 13 14 15 16 17 18 19
ctor: 2
20 21 22 23 24 25 26 27 28 29
ctor: 3
30 31 32 33 34 35 36 37 38 39
ctor: 4
40 41 42 43 44 45 46 47 48 49
ctor: 5
50 51 52 53 54 55 56 57 58 59
$l%+eight in 8aa 2
8 shared <andlerThreads in a ThreadPool
*he (olor6o2 class has no+ become a /ly+eight: the color changing and painting capability
remains JintrinsicK! and the threaded behavior has been made Je2trinsicK.
*he *hread'ool class plays the role of the /actory. As (olor6o2 ob8ects are created! they register
themselves +ith the *hread'ool ob8ect. *he latter launches 4 JhandlerK threads. ?hen each
thread is s+apped into the ('%! it selects a random /ly+eight from the *hread'oolAs cache! and
asks the ob8ect to change(olorEG.
import java.awt.*;
import java.util.Vector;
class ColorBox2 extends Canvas {
private Color curColor = getColor();
Structural patterns 112 of 205
private static Color[] colors = { Color.black, Color.blue, Color.cyan,
Color.darkGray, Color.gray, Color.green, Color.lightGray, Color.red,
Color.magenta, Color.orange, Color.pink, Color.white, Color.yellow };
public ColorBox2( ThreadPool2 tp ) {
tp.register( this );
}
private static Color getColor() {
return colors[ (int)(Math.random() * 1000) % colors.length ];
}
public void changeColor() {
curColor = getColor();
repaint();
}
public void paint( Graphics g ) {
g.setColor( curColor );
g.fillRect( 0, 0, getWidth(), getHeight() );
} }
class ThreadPool2 {
private final int NUM_THREADS = 8;
private Vector cboxes = new Vector();
private int pause;
class HandlerThread extends Thread {
public void run() {
while (true) {
((ColorBox2) cboxes.elementAt(
(int)(Math.random()*1000) % cboxes.size() )).changeColor();
try { Thread.sleep( pause ); } catch( InterruptedException e ) { }
} } }
public ThreadPool2( int p ) {
pause = p;
}
public void register( ColorBox2 r ) {
cboxes.addElement( r );
}
public void start() {
for (int i=0; i < NUM_THREADS; i++) new HandlerThread().start();
} }
public class ColorBoxes2 {
public static void main( String[] args ) {
int size = 8, pause = 10;
if (args.length > 0) size = Integer.parseInt( args[0] );
if (args.length > 1) pause = Integer.parseInt( args[1] );
ThreadPool2 tp = new ThreadPool2( pause );
Frame f = new FrameClose( "ColorBoxes2 - 8 shared HandlerThreads" );
f.setLayout( new GridLayout( size, size ) );
for (int i=0; i < size*size; i++)
f.add( new ColorBox2( tp ) );
f.setSize( 500, 400 );
f.setVisible( true );
Structural patterns 118 of 205
tp.start();
} }
output:
D:> java ColorBoxes 18 50
produces 324 boxes, 8 threads, and 50 millisecond sleep()
performance is very much improved
More e2amples for fly+eight design pattern:
http://sourcemaking.com/design_patterns/fly+eight/8ava/"
http://sourcemaking.com/design_patterns/fly+eight/8ava/)
Pro,% Design Pattern
Intent
$. 'rovide a surrogate or placeholder for another ob8ect to control access to it.
". %se an e2tra level of indirection to support distributed! controlled! or intelligent access.
). Add a +rapper and delegation to protect the real component from undue comple2ity.
Proble*
Uou need to support resource>hungry ob8ects! and you do not +ant to instantiate such ob8ects
unless and until they are actually re=uested by the client.
Discussion
&esign a surrogate! or pro2y! ob8ect that: instantiates the real ob8ect the first time the client
makes a re=uest of the pro2y! remembers the identity of this real ob8ect! and for+ards the
instigating re=uest to this real ob8ect. *hen all subse=uent re=uests are simply for+arded directly
to the encapsulated real ob8ect.
*here are four common situations in +hich the 'ro2y pattern is applicable.
$. A virtual pro2y is a placeholder for Je2pensive to createK ob8ects. *he real ob8ect is only
created +hen a client first re=uests/accesses the ob8ect.
". A remote pro2y provides a local representative for an ob8ect that resides in a different
address space. *his is +hat the JstubK code in 5'( and (756A provides.
). A protective pro2y controls access to a sensitive master ob8ect. *he JsurrogateK ob8ect
checks that the caller has the access permissions re=uired prior to for+arding the
re=uest.
9. A smart pro2y interposes additional actions +hen an ob8ect is accessed. *ypical uses
include:
(ounting the number of references to the real ob8ect so that it can be freed
automatically +hen there are no more references Eaka smart pointerG!
,oading a persistent ob8ect into memory +hen itAs first referenced!
(hecking that the real ob8ect is locked before it is accessed to ensure that no other
ob8ect can change it.
Structural patterns 114 of 205
Structure
6y defining a ub8ect interface! the presence of the 'ro2y ob8ect standing in place of the
5ealub8ect is transparent to the client.
5,a*ple
*he 'ro2y provides a surrogate or place holder to provide access to an ob8ect. A check or bank
draft is a pro2y for funds in an account. A check can be used in place of cash for making
purchases and ultimately controls access to cash in the issuerAs account.
Chec0 list
$. -dentify the leverage or JaspectK that is best implemented as a +rapper or surrogate.
". &efine an interface that +ill make the pro2y and the original component interchangeable.
). (onsider defining a /actory that can encapsulate the decision of +hether a pro2y or
original ob8ect is desirable.
9. *he +rapper class holds a pointer to the real class and implements the interface.
.. *he pointer may be initiali@ed at construction! or on first use.
0. 1ach +rapper method contributes its leverage! and delegates to the +rappee ob8ect.
3ules of thu*b
Adapter provides a different interface to its sub8ect. 'ro2y provides the same interface.
&ecorator provides an enhanced interface.
Structural patterns 120 of 205
&ecorator and 'ro2y have different purposes but similar structures. 6oth describe ho+ to
provide a level of indirection to another ob8ect! and the implementations keep a reference
to the ob8ect to +hich they for+ard re=uests.
Pro,% in C667 Before and after
Before
&irect coupling! lots of start>up and shut>do+n overhead.
class Image
{
int m_id;
static int s_next;
public:
Image()
{
m_id = s_next++;
cout << " $$ ctor: " << m_id << '\n';
}
~Image()
{
cout << " dtor: " << m_id << '\n';
}
void draw()
{
cout << " drawing image " << m_id << '\n';
}
};
int Image::s_next = 1;
int main()
{
Image images[5];
for (int i; true;)
{
cout << "Exit[0], Image[1-5]: ";
cin >> i;
if (i == 0)
break;
images[i - 1].draw();
}
}
output:
$$ ctor: 1
$$ ctor: 2
$$ ctor: 3
$$ ctor: 4
$$ ctor: 5
Exit[0], Image[1-5]: 2
drawing image 2
Exit[0], Image[1-5]: 4
drawing image 4
Exit[0], Image[1-5]: 2
drawing image 2
Structural patterns 121 of 205
Exit[0], Image[1-5]: 0
dtor: 5
dtor: 4
dtor: 3
dtor: 2
dtor: 1
#fter
-nitiali@ation on first use
$. &esign an Je2tra level of indirectionK +rapper class
". *he +rapper class holds a pointer to the real class
). *he pointer is initiali@ed to null
9. ?hen a re=uest comes in! the real ob8ect is created Jon first useK Eaka la@y intiali@ationG
.. *he re=uest is al+ays delegated
class RealImage
{
int m_id;
public:
RealImage(int i)
{
m_id = i;
cout << " $$ ctor: " << m_id << '\n';
}
~RealImage()
{
cout << " dtor: " << m_id << '\n';
}
void draw()
{
cout << " drawing image " << m_id << '\n';
}
};
// 1. Design an "extra level of indirection" wrapper class
class Image
{
// 2. The wrapper class holds a pointer to the real class
RealImage *m_the_real_thing;
int m_id;
static int s_next;
public:
Image()
{
m_id = s_next++;
// 3. Initialized to null
m_the_real_thing = 0;
}
~Image()
{
delete m_the_real_thing;
}
void draw()
Structural patterns 122 of 205
{
// 4. When a request comes in, the real object is
// created "on first use"
if (!m_the_real_thing)
m_the_real_thing = new RealImage(m_id);
// 5. The request is always delegated
m_the_real_thing->draw();
}
};
int Image::s_next = 1;
int main()
{
Image images[5];
for (int i; true;)
{
cout << "Exit[0], Image[1-5]: ";
cin >> i;
if (i == 0)
break;
images[i - 1].draw();
}
}
output:
Exit[0], Image[1-5]: 2
$$ ctor: 2
drawing image 2
Exit[0], Image[1-5]: 4
$$ ctor: 4
drawing image 4
Exit[0], Image[1-5]: 2
drawing image 2
Exit[0], Image[1-5]: 0
dtor: 4
dtor: 2
Pro,% in C66 1
=9>= and ?.= operators gie different results
class Subject
{
public:
virtual void execute() = 0;
};
class RealSubject: public Subject
{
string str;
public:
RealSubject(string s)
{
str = s;
}
Structural patterns 12! of 205
/*virtual*/void execute()
{
cout << str << '\n';
}
};
class ProxySubject: public Subject
{
string first, second, third;
RealSubject *ptr;
public:
ProxySubject(string s)
{
int num = s.find_first_of(' ');
first = s.substr(0, num);
s = s.substr(num + 1);
num = s.find_first_of(' ');
second = s.substr(0, num);
s = s.substr(num + 1);
num = s.find_first_of(' ');
third = s.substr(0, num);
s = s.substr(num + 1);
ptr = new RealSubject(s);
}
~ProxySubject()
{
delete ptr;
}
RealSubject *operator->()
{
cout << first << ' ' << second << ' ';
return ptr;
}
/*virtual*/void execute()
{
cout << first << ' ' << third << ' ';
ptr->execute();
}
};
int main()
{
ProxySubject obj(string("the quick brown fox jumped over the dog"));
obj->execute();
obj.execute();
}
output:
the quick fox jumped over the dog
the brown fox jumped over the dog
Pro,% in C66 2
?# protection pro,% controls access to the original ob(ect=
Structural patterns 12) of 205
class Person
{
string nameString;
static string list[];
static int next;
public:
Person()
{
nameString = list[next++];
}
string name()
{
return nameString;
}
};
string Person::list[] =
{
"Tom", "Dick", "Harry", "Bubba"
};
int Person::next = 0;
class PettyCashProtected
{
int balance;
public:
PettyCashProtected()
{
balance = 500;
}
bool withdraw(int amount)
{
if (amount > balance)
return false;
balance -= amount;
return true;
}
int getBalance()
{
return balance;
}
};
class PettyCash
{
PettyCashProtected realThing;
public:
bool withdraw(Person &p, int amount)
{
if (p.name() == "Tom" || p.name() ==
"Harry" || p.name() == "Bubba")
return realThing.withdraw(amount);
else
return false;
}
int getBalance()
{
Structural patterns 125 of 205
return realThing.getBalance();
}
};
int main()
{
PettyCash pc;
Person workers[4];
for (int i = 0, amount = 100; i < 4; i++, amount += 100)
if (!pc.withdraw(workers[i], amount))
cout << "No money for " << workers[i].name() << '\n';
else
cout << amount << " dollars for " << workers[i].name() << '\n';
cout << "Remaining balance is " << pc.getBalance() << '\n';
}
output:
100 dollars for Tom
No money for Dick
300 dollars for Harry
No money for Bubba
Remaining balance is 100
Pro,% in 8aa
Pro,% design pattern
$. (reate a J+rapperK for a remote! or
e2pensive! or sensitive target
". 1ncapsulate the comple2ity/overhead
of the target in the +rapper
). *he client deals +ith the +rapper
9. *he +rapper delegates to the target
.. *o support plug>compatibility of
+rapper and target! create an interface
import java.io.*; import java.net.*;
// 5. To support plug-compatibility
between
// the wrapper and the target, create an
interface
interface SocketInterface {
String readLine();
void writeLine( String str );
void dispose();
}
public class ProxyDemo {
public static void main( String[] args ) {
// 3. The client deals with the wrapper
SocketInterface socket = new SocketProxy( "127.0.0.1", 8189,
Structural patterns 121 of 205
args[0].equals("first") ? true : false );
String str = null;
boolean skip = true;
while (true) {
if (args[0].equals("second") && skip) {
skip = ! skip;
}
else {
str = socket.readLine();
System.out.println( "Receive - " + str ); // java ProxyDemo first
if (str.equals("quit")) break; // Receive - 123 456
} // Send ---- 234 567
System.out.print( "Send ---- " ); // Receive - 345 678
str = Read.aString(); //
socket.writeLine( str ); // java ProxyDemo second
if (str.equals("quit")) break; // Send ---- 123 456
} // Receive - 234 567
socket.dispose(); // Send ---- 345 678
}
}
class SocketProxy implements SocketInterface {
// 1. Create a "wrapper" for a remote,
// or expensive, or sensitive target
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public SocketProxy( String host, int port, boolean wait ) {
try {
if (wait) {
// 2. Encapsulate the complexity/overhead of the target in the wrapper
ServerSocket server = new ServerSocket( port );
socket = server.accept();
} else
socket = new Socket( host, port );
in = new BufferedReader( new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter( socket.getOutputStream(), true );
} catch( IOException e ) {
e.printStackTrace();
}
}
public String readLine() {
String str = null;
try {
str = in.readLine();
} catch( IOException e ) {
e.printStackTrace();
}
return str;
}
public void writeLine( String str ) {
// 4. The wrapper delegates to the target
out.println( str );
Structural patterns 122 of 205
}
public void dispose() {
try {
socket.close();
} catch( IOException e ) {
e.printStackTrace();
}
}
}
Behaioral patterns 128 of 205
Behaioral patterns
Introduction
-n soft+are engineering! behavioral design patterns are design patterns that identify common
communication patterns bet+een ob8ects and reali@e these patterns. 6y doing so! these patterns
increase fle2ibility in carrying out this communication.
Chain of responsibilit%
A +ay of passing a re=uest bet+een a chain of ob8ects
Co**and
1ncapsulate a command re=uest as an ob8ect
Interpreter
A +ay to include language elements in a program
Iterator
e=uentially access the elements of a collection
&ediator
&efines simplified communication bet+een classes
&e*ento
(apture and restore an ob8ectAs internal state
-ull 'b(ect
&esigned to act as a default value of an ob8ect
'bserer
A +ay of notifying change to a number of classes
State
Alter an ob8ectAs behavior +hen its state changes
Strateg%
1ncapsulates an algorithm inside a class
Te*plate *ethod
&efer the e2act steps of an algorithm to a subclass
.isitor
&efines a ne+ operation to a class +ithout change
3ules of thu*b
$. 6ehavioral patterns are concerned +ith the assignment of responsibilities bet+een
ob8ects! or! encapsulating behavior in an ob8ect and delegating re=uests to it.
". (hain of responsibility! (ommand! Mediator! and 7bserver! address ho+ you can decouple
senders and receivers! but +ith different trade>offs. (hain of responsibility passes a
sender re=uest along a chain of potential receivers. (ommand normally specifies a sender>
Behaioral patterns 124 of 205
receiver connection +ith a subclass. Mediator has senders and receivers reference each
other indirectly. 7bserver defines a very decoupled interface that allo+s for multiple
receivers to be configured at run>time.
). (hain of responsibility can use (ommand to represent re=uests as ob8ects.
9. (hain of responsibility is often applied in con8unction +ith (omposite. *here! a
componentAs parent can act as its successor.
.. (ommand and Memento act as magic tokens to be passed around and invoked at a later
time. -n (ommand! the token represents a re=uestI in Memento! it represents the internal
state of an ob8ect at a particular time. 'olymorphism is important to (ommand! but not to
Memento because its interface is so narro+ that a memento can only be passed as a value.
0. (ommand can use Memento to maintain the state re=uired for an undo operation.
3. Macro(ommands can be implemented +ith (omposite.
4. A (ommand that must be copied before being placed on a history list acts as a 'rototype.
:. -nterpreter can use tate to define parsing conte2ts.
$#. *he abstract synta2 tree of -nterpreter is a (omposite Etherefore -terator and ;isitor are
also applicableG.
$$. *erminal symbols +ithin -nterpreterAs abstract synta2 tree can be shared +ith /ly+eight.
$". -terator can traverse a (omposite. ;isitor can apply an operation over a (omposite.
$). 'olymorphic -terators rely on /actory Methods to instantiate the appropriate -terator
subclass.
$9. Mediator and 7bserver are competing patterns. *he difference bet+een them is that
7bserver distributes communication by introducing JobserverK and Jsub8ectK ob8ects!
+hereas a Mediator ob8ect encapsulates the communication bet+een other ob8ects. ?eAve
found it easier to make reusable 7bservers and ub8ects than to make reusable
Mediators.
$.. 7n the other hand! Mediator can leverage 7bserver for dynamically registering colleagues
and communicating +ith them.
$0. Mediator is similar to /acade in that it abstracts functionality of e2isting classes. Mediator
abstracts/centrali@es arbitrary communication bet+een colleague ob8ects! it routinely
Jadds valueK! and it is kno+n/referenced by the colleague ob8ects Ei.e. it defines a
multidirectional protocolG. -n contrast! /acade defines a simpler interface to a subsystem!
it doesnAt add ne+ functionality! and it is not kno+n by the subsystem classes Ei.e. it
defines a unidirectional protocol +here it makes re=uests of the subsystem classes but not
vice versaG.
$3. Memento is often used in con8unction +ith -terator. An -terator can use a Memento to
capture the state of an iteration. *he -terator stores the Memento internally.
$4. tate is like trategy e2cept in its intent.
$:. /ly+eight e2plains +hen and ho+ tate ob8ects can be shared.
"#. tate ob8ects are often ingletons.
"$. trategy lets you change the guts of an ob8ect. &ecorator lets you change the skin.
"". trategy is to algorithm. as 6uilder is to creation.
"). trategy has " different implementations! the first is similar to tate. *he difference is in
binding times Etrategy is a bind>once pattern! +hereas tate is more dynamicG.
"9. trategy ob8ects often make good /ly+eights.
Behaioral patterns 1!0 of 205
".. trategy is like *emplate method e2cept in its granularity.
"0. *emplate method uses inheritance to vary part of an algorithm. trategy uses delegation
to vary the entire algorithm.
"3. *he ;isitor pattern is like a more po+erful (ommand pattern because the visitor may
initiate +hatever is appropriate for the kind of ob8ect it encounters.
Chain of 3esponsibilit%
Intent
Avoid coupling the sender of a re=uest to its receiver by giving more than one ob8ect a
chance to handle the re=uest. (hain the receiving ob8ects and pass the re=uest along the
chain until an ob8ect handles it.
,aunch>and>leave re=uests +ith a single processing pipeline that contains many possible
handlers.
An ob8ect>oriented linked list +ith recursive traversal.
Proble*
*here is a potentially variable number of JhandlerK or Jprocessing elementK or JnodeK ob8ects!
and a stream of re=uests that must be handled. Need to efficiently process the re=uests +ithout
hard>+iring handler relationships and precedence! or re=uest>to>handler mappings.
Discussion
1ncapsulate the processing elements inside a JpipelineK abstractionI and have clients Jlaunch
and leaveK their re=uests at the entrance to the pipeline.
*he pattern chains the receiving ob8ects together! and then passes any re=uest messages from
ob8ect to ob8ect until it reaches an ob8ect capable of handling the message. *he number and type
of handler ob8ects isnAt kno+n a priori! they can be configured dynamically. *he chaining
mechanism uses recursive composition to allo+ an unlimited number of handlers to be linked.
(hain of 5esponsibility simplifies ob8ect interconnections. -nstead of senders and receivers
maintaining references to all candidate receivers! each sender keeps a single reference to the
head of the chain! and each receiver keeps a single reference to its immediate successor in the
chain.
Make sure there e2ists a Jsafety netK to JcatchK any re=uests +hich go unhandled.
&o not use (hain of 5esponsibility +hen each re=uest is only handled by one handler! or! +hen
the client ob8ect kno+s +hich service ob8ect should handle the re=uest.
Structure
*he derived classes kno+ ho+ to satisfy (lient re=uests. -f the JcurrentK ob8ect is not available or
Behaioral patterns 1!1 of 205
sufficient! then it delegates to the base class! +hich delegates to the Jne2tK ob8ect! and the circle
of life continues.
Multiple handlers could contribute to the handling of each re=uest. *he re=uest can be passed
do+n the entire length of the chain! +ith the last link being careful not to delegate to a Jnull
ne2tK.
5,a*ple
*he (hain of 5esponsibility pattern avoids coupling the sender of a re=uest to the receiver by
giving more than one ob8ect a chance to handle the re=uest. A*M use the (hain of 5esponsibility
in money giving mechanism.
Chec0 list
$. *he base class maintains a Jne2tK pointer.
". 1ach derived class implements its contribution for handling the re=uest.
). -f the re=uest needs to be Jpassed onK! then the derived class Jcalls backK to the base
class! +hich delegates to the Jne2tK pointer.
9. *he client Eor some third partyG creates and links the chain E+hich may include a link from
the last node to the root nodeG.
.. *he client Jlaunches and leavesK each re=uest +ith the root of the chain.
0. 5ecursive delegation produces the illusion of magic.
3ules of thu*b
(hain of 5esponsibility! (ommand! Mediator! and 7bserver! address ho+ you can decouple
senders and receivers! but +ith different trade>offs. (hain of 5esponsibility passes a
sender re=uest along a chain of potential receivers.
(hain of 5esponsibility can use (ommand to represent re=uests as ob8ects.
(hain of 5esponsibility is often applied in con8unction +ith (omposite. *here! a
componentAs parent can act as its successor.
Chain of 3esponsibilit% in C66
Chain of 3esponsibilit% design pattern
Behaioral patterns 1!2 of 205
$. 'ut a Jne2tK pointer in the base class
". *he JchainK method in the base class al+ays delegates to the ne2t ob8ect
). -f the derived classes cannot handle! they delegate to the base class
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
class Base
{
Base *next; // 1. "next" pointer in the base class
public:
Base()
{
next = 0;
}
void setNext(Base *n)
{
next = n;
}
void add(Base *n)
{
if (next)
next->add(n);
else
next = n;
}
// 2. The "chain" method in the base class always delegates to the next obj
virtual void handle(int i)
{
next->handle(i);
}
};
class Handler1: public Base
{
public:
/*virtual*/void handle(int i)
{
if (rand() % 3)
{
// 3. Don't handle requests 3 times out of 4
cout << "H1 passsed " << i << " ";
Base::handle(i); // 3. Delegate to the base class
}
else
cout << "H1 handled " << i << " ";
}
};
class Handler2: public Base
{
public:
/*virtual*/void handle(int i)
Behaioral patterns 1!! of 205
{
if (rand() % 3)
{
cout << "H2 passsed " << i << " ";
Base::handle(i);
}
else
cout << "H2 handled " << i << " ";
}
};
class Handler3: public Base
{
public:
/*virtual*/void handle(int i)
{
if (rand() % 3)
{
cout << "H3 passsed " << i << " ";
Base::handle(i);
}
else
cout << "H3 handled " << i << " ";
}
};
int main()
{
srand(time(0));
Handler1 root;
Handler2 two;
Handler3 thr;
root.add(&two);
root.add(&thr);
thr.setNext(&root);
for (int i = 1; i < 10; i++)
{
root.handle(i);
cout << '\n';
}
}
H1 passsed 1 H2 passsed 1 H3 passsed 1 H1 passsed 1 H2 handled 1
H1 handled 2
H1 handled 3
H1 passsed 4 H2 passsed 4 H3 handled 4
H1 passsed 5 H2 handled 5
H1 passsed 6 H2 passsed 6 H3 passsed 6 H1 handled 6
H1 passsed 7 H2 passsed 7 H3 passsed 7 H1 passsed 7 H2 handled 7
H1 handled 8
H1 passsed 9 H2 passsed 9 H3 handled 9
Chain of 3esponsibilit% in C667 Chain and Co*posite
$. 'ut a Jne2tK pointer in the base class
Behaioral patterns 1!) of 205
". *he JchainK method in the base class al+ays delegates to the ne2t ob8ect
). -f the derived classes cannot handle! they delegate to the base class
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
class Component
{
int value;
Component *next; // 1. "next" pointer in the base class
public:
Component(int v, Component *n)
{
value = v;
next = n;
}
void setNext(Component *n)
{
next = n;
}
virtual void traverse()
{
cout << value << ' ';
}
// 2. The "chain" method in the base class always delegates to the next obj
virtual void volunteer()
{
next->volunteer();
}
};
class Primitive: public Component
{
public:
Primitive(int val, Component *n = 0): Component(val, n){}
/*virtual*/void volunteer()
{
Component::traverse();
// 3. Primitive objects don't handle volunteer requests 5 times out of 6
if (rand() *100 % 6 != 0)
// 3. Delegate to the base class
Component::volunteer();
}
};
class Composite: public Component
{
vector < Component * > children;
public:
Composite(int val, Component *n = 0): Component(val, n){}
void add(Component *c)
{
children.push_back(c);
}
Behaioral patterns 1!5 of 205
/*virtual*/void traverse()
{
Component::traverse();
for (int i = 0; i < children.size(); i++)
children[i]->traverse();
}
// 3. Composite objects never handle volunteer requests
/*virtual*/void volunteer()
{
Component::volunteer();
}
};
int main()
{
srand(time(0)); // 1
Primitive seven(7); // |
Primitive six(6, &seven); // +-- 2
Composite three(3, &six); // | |
three.add(&six);
three.add(&seven); // | +-- 4 5
Primitive five(5, &three); // |
Primitive four(4, &five); // +-- 3
Composite two(2, &four); // | |
two.add(&four);
two.add(&five); // | +-- 6 7
Composite one(1, &two); // |
Primitive nine(9, &one); // +-- 8 9
Primitive eight(8, &nine);
one.add(&two);
one.add(&three);
one.add(&eight);
one.add(&nine);
seven.setNext(&eight);
cout << "traverse: ";
one.traverse();
cout << '\n';
for (int i = 0; i < 8; i++)
{
one.volunteer();
cout << '\n';
}
}
traverse: 1 2 4 5 3 6 7 8 9
4
4 5 6 7
4 5 6 7 8 9 4 5 6 7 8 9 4
4
4 5 6
4 5
4 5
4 5 6 7 8 9 4 5 6 7 8 9 4 5 6
Chain of 3esponsibilit% in 8aa7 Before and after
Behaioral patterns 1!1 of 205
Before
*he client is responsible for stepping through the JlistK of Dandler ob8ects! and determining
+hen the re=uest has been handled.
class Handler
{
private static java.util.Random s_rn = new java.util.Random();
private static int s_next = 1;
private int m_id = s_next++;
public boolean handle(int num)
{
if (s_rn.nextInt(4) != 0)
{
System.out.print(m_id + "-busy ");
return false;
}
System.out.println(m_id + "-handled-" + num);
return true;
}
}
public class ChainDemo
{
public static void main(String[] args)
{
Handler[] nodes =
{
new Handler(), new Handler(), new Handler(), new Handler()
};
for (int i = 1, j; i < 10; i++)
{
j = 0;
while (!nodes[j].handle(i))
j = (j + 1) % nodes.length;
}
}
}
1-busy 2-busy 3-busy 4-busy 1-busy 2-handled-1
1-busy 2-busy 3-handled-2
1-busy 2-busy 3-busy 4-handled-3
1-busy 2-busy 3-busy 4-busy 1-busy 2-busy
3-handled-4
1-busy 2-busy 3-handled-5
1-handled-6
1-busy 2-handled-7
1-busy 2-busy 3-busy 4-busy 1-busy 2-busy
3-busy 4-handled-8
1-busy 2-handled-9
#fter
*he client submits each re=uest to the JchainK abstraction and is decoupled from all subse=uent
processing.
Behaioral patterns 1!2 of 205
class Handler
{
private static java.util.Random s_rn = new java.util.Random();
private static int s_next = 1;
private int m_id = s_next++;
private Handler m_next;
public void add(Handler next)
{
if (m_next == null)
m_next = next;
else
m_next.add(next);
}
public void wrap_around(Handler root)
{
if (m_next == null)
m_next = root;
else
m_next.wrap_around(root);
}
public void handle(int num)
{
if (s_rn.nextInt(4) != 0)
{
System.out.print(m_id + "-busy ");
m_next.handle(num);
}
else
System.out.println(m_id + "-handled-" + num);
}
}
public class ChainDemo
{
public static void main(String[] args)
{
Handler chain_root = new Handler();
chain_root.add(new Handler());
chain_root.add(new Handler());
chain_root.add(new Handler());
chain_root.wrap_around(chain);
for (int i = 1; i < 10; i++)
chain_root.handle(i);
}
}
1-busy 2-busy 3-handled-1
1-busy 2-busy 3-busy 4-busy 1-handled-2
1-busy 2-busy 3-busy 4-busy 1-busy 2-busy
3-busy 4-busy 1-handled-3
1-busy 2-handled-4
1-busy 2-busy 3-busy 4-handled-5
1-busy 2-busy 3-busy 4-busy 1-busy 2-handled-6
1-busy 2-handled-7
1-handled-8
1-busy 2-busy 3-handled-9
Behaioral patterns 1!8 of 205
Chain of 3esponsibilit% in 8aa
/ots of client effort to *anage a list of Processors
public class ChainBefore {
interface Image {
String process();
}
static class IR implements Image {
public String process() {
return "IR";
}
}
static class LS implements Image {
public String process() {
return "LS";
}
}
static class Processor {
private static java.util.Random rn = new java.util.Random();
private static int nextId = 1;
private int id = nextId++;
public boolean handle( Image img ) {
if (rn.nextInt(2) != 0) {
System.out.println( " Processor " + id + " is busy" );
return false;
}
System.out.println( "Processor " + id + " - " + img.process() );
return true;
}
}
public static void main( String[] args ) {
Image[] input = { new IR(), new IR(), new LS(), new IR(), new LS(), new LS()
};
Processor[] procs = { new Processor(), new Processor(), new Processor() };
for (int i=0, j; i < input.length; i++) {
j = 0;
while ( ! procs[j].handle( input[i] ))
j = (j+1) % procs.length;
}
}
}
Processor 1 - IR
Processor 1 is busy
Processor 2 is busy
Processor 3 is busy
Processor 1 is busy
Processor 2 is busy
Processor 3 - IR
Processor 1 is busy
Processor 2 - LS
Processor 1 - IR
Behaioral patterns 1!4 of 205
Processor 1 - LS
Processor 1 is busy
Processor 2 is busy
Processor 3 is busy
Processor 1 - LS
Co**and Design Pattern
Intent
1ncapsulate a re=uest as an ob8ect! thereby letting you parameteri@e clients +ith different
re=uests! =ueue or log re=uests! and support undoable operations.
'romote Jinvocation of a method on an ob8ectK to full ob8ect status
An ob8ect>oriented callback
Proble*
Need to issue re=uests to ob8ects +ithout kno+ing anything about the operation being re=uested
or the receiver of the re=uest.
Discussion
(ommand decouples the ob8ect that invokes the operation from the one that kno+s ho+ to
perform it. *o achieve this separation! the designer creates an abstract base class that maps a
receiver Ean ob8ectG +ith an action Ea pointer to a member functionG. *he base class contains an
e2ecuteEG method that simply calls the action on the receiver.
All clients of (ommand ob8ects treat each ob8ect as a Jblack bo2K by simply invoking the ob8ectAs
virtual e2ecuteEG method +henever the client re=uires the ob8ectAs JserviceK.
A (ommand class holds some subset of the follo+ing: an ob8ect! a method to be applied to the
ob8ect! and the arguments to be passed +hen the method is applied. *he (ommandAs Je2ecuteK
method then causes the pieces to come together.
e=uences of (ommand ob8ects can be assembled into composite Eor macroG commands.
Structure
*he client that creates a command is not the same client that e2ecutes it. *his separation
provides fle2ibility in the timing and se=uencing of commands. Materiali@ing commands as
ob8ects means they can be passed! staged! shared! loaded in a table! and other+ise instrumented
or manipulated like any other ob8ect.
Behaioral patterns 1)0 of 205
(ommand ob8ects can be thought of as JtokensK that are created by one client that kno+s +hat
need to be done! and passed to another client that has the resources for doing it.
5,a*ple
*he (ommand pattern allo+s re=uests to be encapsulated as ob8ects! thereby allo+ing clients to
be parameteri@ed +ith different re=uests. *he JcheckK at a diner is an e2ample of a (ommand
pattern. *he +aiter or +aitress takes an order or command from a customer and encapsulates
that order by +riting it on the check. *he order is then =ueued for a short order cook. Note that
the pad of JchecksK used by each +aiter is not dependent on the menu! and therefore they can
support commands to cook many different items.
Chec0 list
$. &efine a (ommand interface +ith a method signature like e2ecuteEG.
". (reate one or more derived classes that encapsulate some subset of the follo+ing: a
JreceiverK ob8ect! the method to invoke! the arguments to pass.
). -nstantiate a (ommand ob8ect for each deferred e2ecution re=uest.
9. 'ass the (ommand ob8ect from the creator Eaka senderG to the invoker Eaka receiverG.
Behaioral patterns 1)1 of 205
.. *he invoker decides +hen to e2ecuteEG.
3ules of thu*b
(hain of 5esponsibility! (ommand! Mediator! and 7bserver! address ho+ you can decouple
senders and receivers! but +ith different trade>offs. (ommand normally specifies a
sender>receiver connection +ith a subclass.
(hain of 5esponsibility can use (ommand to represent re=uests as ob8ects.
(ommand and Memento act as magic tokens to be passed around and invoked at a later
time. -n (ommand! the token represents a re=uestI in Memento! it represents the internal
state of an ob8ect at a particular time. 'olymorphism is important to (ommand! but not to
Memento because its interface is so narro+ that a memento can only be passed as a value.
(ommand can use Memento to maintain the state re=uired for an undo operation.
Macro(ommands can be implemented +ith (omposite.
A (ommand that must be copied before being placed on a history list acts as a 'rototype.
*+o important aspects of the (ommand pattern: interface separation Ethe invoker is
isolated from the receiverG! time separation Estores a ready>to>go processing re=uest thatAs
to be stated laterG.
Co**and in C667 Before and after
Before
the client has to =uery the JtypeK of each ob8ect! and manually invoke the desired method.
class Giant
{
public:
enum Type
{
Fee, Phi, Pheaux
};
Giant()
{
m_id = s_next++;
m_type = (Type)(m_id % 3);
}
Type get_type()
{
return m_type;
}
void fee()
{
cout << m_id << "-fee ";
}
void phi()
{
cout << m_id << "-phi ";
}
void pheaux()
{
cout << m_id << "-pheaux ";
Behaioral patterns 1)2 of 205
}
private:
Type m_type;
int m_id;
static int s_next;
};
int Giant::s_next = 0;
template <typename T> class Queue
{
public:
Queue()
{
m_add = m_remove = 0;
}
void enque(T *c)
{
m_array[m_add] = c;
m_add = (m_add + 1) % SIZE;
}
T *deque()
{
int temp = m_remove;
m_remove = (m_remove + 1) % SIZE;
return m_array[temp];
}
private:
enum
{
SIZE = 8
};
T *m_array[SIZE];
int m_add, m_remove;
};
int main()
{
Queue que;
Giant input[6], *bad_guy;
for (int i = 0; i < 6; i++)
que.enque(&input[i]);
for (int i = 0; i < 6; i++)
{
bad_guy = que.deque();
if (bad_guy->get_type() == Giant::Fee)
bad_guy->fee();
else if (bad_guy->get_type() == Giant::Phi)
bad_guy->phi();
else if (bad_guy->get_type() == Giant::Pheaux)
bad_guy->pheaux();
}
cout << '\n';
}
Behaioral patterns 1)! of 205
0-fee 1-phi 2-pheaux 3-fee 4-phi 5-pheaux
#fter
the desired method is encapsulated in each (ommand ob8ect.
class Giant
{
public:
Giant()
{
m_id = s_next++;
}
void fee()
{
cout << m_id << "-fee ";
}
void phi()
{
cout << m_id << "-phi ";
}
void pheaux()
{
cout << m_id << "-pheaux ";
}
private:
int m_id;
static int s_next;
};
int Giant::s_next = 0;
class Command
{
public:
typedef void(Giant:: *Action)();
Command(Giant *object, Action method)
{
m_object = object;
m_method = method;
}
void execute()
{
(m_object-> *m_method)();
}
private:
Giant *m_object;
Action m_method;
};
template <typename T> class Queue
{
public:
Queue()
{
m_add = m_remove = 0;
Behaioral patterns 1)) of 205
}
void enque(T *c)
{
m_array[m_add] = c;
m_add = (m_add + 1) % SIZE;
}
T *deque()
{
int temp = m_remove;
m_remove = (m_remove + 1) % SIZE;
return m_array[temp];
}
private:
enum
{
SIZE = 8
};
T *m_array[SIZE];
int m_add, m_remove;
};
int main()
{
Queue que;
Command *input[] =
{
new Command(new Giant, &Giant::fee), new Command(new Giant, &Giant::phi),
new Command(new Giant, &Giant::pheaux), new Command(new Giant, &Giant
::fee), new Command(new Giant, &Giant::phi), new Command(new Giant,
&Giant::pheaux)
};
for (int i = 0; i < 6; i++)
que.enque(input[i]);
for (int i = 0; i < 6; i++)
que.deque()->execute();
cout << '\n';
}
0-fee 1-phi 2-pheaux 3-fee 4-phi 5-pheaux
Co**and in C66
Co**and design pattern
$. (reate a class that encapsulates some number of the follo+ing:
a JreceiverK ob8ect
the method to invoke
the arguments to pass
". -nstantiate an ob8ect for each JcallbackK
). 'ass each ob8ect to its future JsenderK
Behaioral patterns 1)5 of 205
9. ?hen the sender is ready to callback to the receiver! it calls e2ecuteEG
#include <iostream> #include <string> using namespace std;
class Person;
class Command
{
// 1. Create a class that encapsulates an object and a member function
// a pointer to a member function (the attribute's name is "method")
Person *object; //
void(Person:: *method)();
public:
Command(Person *obj = 0, void(Person:: *meth)() = 0)
{
object = obj; // the argument's name is "meth"
method = meth;
}
void execute()
{
(object-> *method)(); // invoke the method on the object
}
};
class Person
{
string name;
// cmd is a "black box", it is a method invocation
// promoted to "full object status"
Command cmd;
public:
Person(string n, Command c): cmd(c)
{
name = n;
}
void talk()
{
// "this" is the sender, cmd has the receiver
cout << name << " is talking" << endl;
cmd.execute(); // ask the "black box" to callback the receiver
}
void passOn()
{
cout << name << " is passing on" << endl;

// 4. When the sender is ready to callback to the receiver,
// it calls execute()
cmd.execute();
}
void gossip()
{
cout << name << " is gossiping" << endl;
cmd.execute();
}
void listen()
{
Behaioral patterns 1)1 of 205
cout << name << " is listening" << endl;
}
};
int main()
{
// Fred will "execute" Barney which will result in a call to passOn()
// Barney will "execute" Betty which will result in a call to gossip()
// Betty will "execute" Wilma which will result in a call to listen()
Person wilma("Wilma", Command());
// 2. Instantiate an object for each "callback"
// 3. Pass each object to its future "sender"
Person betty("Betty", Command(&wilma, &Person::listen));
Person barney("Barney", Command(&betty, &Person::gossip));
Person fred("Fred", Command(&barney, &Person::passOn));
fred.talk();
}
Fred is talking
Barney is passing on
Betty is gossiping
Wilma is listening
Co**and in C667 Si*ple and :*acro: co**ands
&iscussion. 1ncapsulate a re=uest as an ob8ect. imple(ommand maintains a binding bet+een a
receiver ob8ect and an action stored as a pointer to a member function. Macro(ommand
maintains a se=uence of (ommands. No e2plicit receiver is re=uired because the subcommands
already define their receiver. Macro(ommand may contain Macro(ommands.
#include <iostream>
#include <vector>
using namespace std;
class Number
{
public:
void dubble(int &value)
{
value *= 2;
}
};
class Command
{
public:
virtual void execute(int &) = 0;
};
class SimpleCommand: public Command
{
typedef void(Number:: *Action)(int &);
Number *receiver;
Action action;
public:
SimpleCommand(Number *rec, Action act)
Behaioral patterns 1)2 of 205
{
receiver = rec;
action = act;
}
/*virtual*/void execute(int &num)
{
(receiver-> *action)(num);
}
};
class MacroCommand: public Command
{
vector < Command * > list;
public:
void add(Command *cmd)
{
list.push_back(cmd);
}
/*virtual*/void execute(int &num)
{
for (int i = 0; i < list.size(); i++)
list[i]->execute(num);
}
};
int main()
{
Number object;
Command *commands[3];
commands[0] = &SimpleCommand(&object, &Number::dubble);
MacroCommand two;
two.add(commands[0]);
two.add(commands[0]);
commands[1] = &two;
MacroCommand four;
four.add(&two);
four.add(&two);
commands[2] = &four;
int num, index;
while (true)
{
cout << "Enter number selection (0=2x 1=4x 2=16x): ";
cin >> num >> index;
commands[index]->execute(num);
cout << " " << num << '\n';
}
}
Enter number selection (0=2x 1=4x 2=16x): 3 0
6
Enter number selection (0=2x 1=4x 2=16x): 3 1
12
Enter number selection (0=2x 1=4x 2=16x): 3 2
Behaioral patterns 1)8 of 205
48
Enter number selection (0=2x 1=4x 2=16x): 4 0
8
Enter number selection (0=2x 1=4x 2=16x): 4 1
16
Enter number selection (0=2x 1=4x 2=16x): 4 2
64
Co**and in 8aa7 Decoupling producer fro* consu*er
import java.util.*;
public class CommandQueue {
interface Command { void execute(); }
static class DomesticEngineer implements Command {
public void execute() {
System.out.println( "take out the trash" );
} }
static class Politician implements Command {
public void execute() {
System.out.println( "take money from the rich, take votes from the poor" );
} }
static class Programmer implements Command {
public void execute() {
System.out.println( "sell the bugs, charge extra for the fixes" );
} }
public static List produceRequests() {
List queue = new ArrayList();
queue.add( new DomesticEngineer() );
queue.add( new Politician() );
queue.add( new Programmer() );
return queue;
}
public static void workOffRequests( List queue ) {
for (Iterator it = queue.iterator(); it.hasNext(); )
((Command)it.next()).execute();
}
public static void main( String[] args ) {
List queue = produceRequests();
workOffRequests( queue );
}}
take out the trash
take money from the rich, take votes from the poor
sell the bugs, charge extra for the fixed
Co**and in 8aa
8aa reflection and the Co**and design pattern
Behaioral patterns 1)4 of 205
Motivation. Jometimes it is necessary to issue re=uests to ob8ects +ithout kno+ing anything
about the operation being re=uested or the receiver of the re=uest.K *he (ommand design
pattern suggests encapsulating EJ+rappingKG in an ob8ect all Eor someG of the follo+ing: an ob8ect!
a method name! and some arguments. Mava does not support Jpointers to methodsK! but its
reflection capability +ill do nicely. *he JcommandK is a black bo2 to the JclientK. All the client
does is call Je2ecuteEGK on the opa=ue ob8ect.
import java.lang.reflect.*;
public class CommandReflect {
private int state;
public CommandReflect( int in ) {
state = in;
}
public int addOne( Integer one ) {
return state + one.intValue();
}
public int addTwo( Integer one, Integer two ) {
return state + one.intValue() + two.intValue();
}
static public class Command {
private Object receiver; // the "encapsulated" object
private Method action; // the "pre-registered" request
private Object[] args; // the "pre-registered" arg list
public Command( Object obj, String methodName, Object[] arguments ) {
receiver = obj;
args = arguments;
Class cls = obj.getClass(); // get the object's "Class"
Class[] argTypes = new Class[args.length];
for (int i=0; i < args.length; i++) // get the "Class" for each
argTypes[i] = args[i].getClass(); // supplied argument
// get the "Method" data structure with the correct name and signature
try { action = cls.getMethod( methodName, argTypes ); }
catch( NoSuchMethodException e ) { System.out.println( e ); }
}
public Object execute() {
// in C++, you do something like --- return receiver->action( args );
try { return action.invoke( receiver, args ); }
catch( IllegalAccessException e ) { System.out.println( e ); }
catch( InvocationTargetException e ) { System.out.println( e ); }
return null;
} }
public static void main( String[] args ) {
CommandReflect[] objs = { new CommandReflect(1), new CommandReflect(2) };
System.out.print( "Normal call results: " );
System.out.print( objs[0].addOne( new Integer(3) ) + " " );
System.out.print( objs[1].addTwo( new Integer(4),
new Integer(5) ) + " " );
Command[] cmds = {
new Command( objs[0], "addOne", new Integer[] { new Integer(3) } ),
new Command( objs[1], "addTwo", new Integer[] { new Integer(4),
new Integer(5) } ) };
System.out.print( "\nReflection results: " );
for (int i=0; i < cmds.length; i++)
Behaioral patterns 150 of 205
System.out.print( cmds[i].execute() + " " );
System.out.println();
} }
Normal call results: 4 11 // 1 + 3 = 4 // 2 + 4 + 5 = 11
Reflection results: 4 11
Interpreter Design Pattern
Intent
Civen a language! define a representation for its grammar along +ith an interpreter that uses the
representation to interpret sentences in the language.
Map a domain to a language! the language to a grammar! and the grammar to a hierarchical
ob8ect>oriented design.
Proble*
A class of problems occurs repeatedly in a +ell>defined and +ell>understood domain. -f the
domain +ere characteri@ed +ith a JlanguageK! then problems could be easily solved +ith an
interpretation JengineK.
Discussion
*he -nterpreter pattern discusses: defining a domain language Ei.e. problem characteri@ationG as
a simple language grammar! representing domain rules as language sentences! and interpreting
these sentences to solve the problem. *he pattern uses a class to represent each grammar rule.
And since grammars are usually hierarchical in structure! an inheritance hierarchy of rule classes
maps nicely.
An abstract base class specifies the method interpretEG. 1ach concrete subclass implements
interpretEG by accepting Eas an argumentG the current state of the language stream! and adding
its contribution to the problem solving process.
Structure
-nterpreter suggests modeling the domain +ith a recursive grammar. 1ach rule in the grammar is
either a VcompositeA Ea rule that references other rulesG or a terminal Ea leaf node in a tree
structureG. -nterpreter relies on the recursive traversal of the (omposite pattern to interpret the
VsentencesA it is asked to process.
Behaioral patterns 151 of 205
5,a*ple
*he -ntepreter pattern defines a grammatical representation for a language and an interpreter to
interpret the grammar. Musicians are e2amples of -nterpreters. *he pitch of a sound and its
duration can be represented in musical notation on a staff. *his notation provides the language of
music. Musicians playing the music from the score are able to reproduce the original pitch and
duration of each sound represented.
Chec0 list
$. &ecide if a Jlittle languageK offers a 8ustifiable return on investment.
". &efine a grammar for the language.
). Map each production in the grammar to a class.
9. 7rgani@e the suite of classes into the structure of the (omposite pattern.
.. &efine an interpretE(onte2tG method in the (omposite hierarchy.
0. *he (onte2t ob8ect encapsulates the current state of the input and output as the former is
parsed and the latter is accumulated. -t is manipulated by each grammar class as the
JinterpretingK process transforms the input into the output.
3ules of thu*b
(onsidered in its most general form Ei.e. an operation distributed over a class hierarchy
based on the (omposite patternG! nearly every use of the (omposite pattern +ill also
contain the -nterpreter pattern. 6ut the -nterpreter pattern should be reserved for those
cases in +hich you +ant to think of this class hierarchy as defining a language.
-nterpreter can use tate to define parsing conte2ts.
*he abstract synta2 tree of -nterpreter is a (omposite Etherefore -terator and ;isitor are
also applicableG.
*erminal symbols +ithin -nterpreterAs abstract synta2 tree can be shared +ith /ly+eight.
*he pattern doesnAt address parsing. ?hen the grammar is very comple2! other
Behaioral patterns 152 of 205
techni=ues Esuch as a parserG are more appropriate.
Interpreter in C66
"sing Interpreter pattern +ith Te*plate &ethod
&iscussion. %ses a class hierarchy to represent the grammar given belo+. ?hen a roman numeral
is provided! the class hierarchy validates and interprets the string. 5N-nterpreter JhasK 9 sub>
interpreters. 1ach sub>interpreter receives the Jconte2tK Eremaining unparsed string and
cumulative parsed valueG and contributes its share to the processing. ub>interpreters simply
define the *emplate Methods declared in the base class 5N-nterpreter.
romanNumeral ::X YthousandsZ YhundredsZ YtensZ YonesZ
thousands! hundreds! tens! ones ::X nine [ four [ YfiveZ YoneZ YoneZ YoneZ
nine ::X B(MB [ BN(B [ B-NB
four ::X B(&B [ BN,B [ B-;B
five ::X <&< [ <,< [ <;<
one ::X <M< [ <(< [ <N< [ <-<
#include <iostream.h>
#include <string.h>
class Thousand;
class Hundred;
class Ten;
class One;
class RNInterpreter
{
public:
RNInterpreter(); // ctor for client
RNInterpreter(int){}
// ctor for subclasses, avoids infinite loop
int interpret(char*); // interpret() for client
virtual void interpret(char *input, int &total)
{
// for internal use
int index;
index = 0;
if (!strncmp(input, nine(), 2))
{
total += 9 * multiplier();
index += 2;
}
else if (!strncmp(input, four(), 2))
{
total += 4 * multiplier();
index += 2;
}
else
{
if (input[0] == five())
{
total += 5 * multiplier();
index = 1;
Behaioral patterns 15! of 205
}
else
index = 0;
for (int end = index + 3; index < end; index++)
if (input[index] == one())
total += 1 * multiplier();
else
break;
}
strcpy(input, &(input[index]));
} // remove leading chars processed
protected:
// cannot be pure virtual because client asks for instance
virtual char one(){}
virtual char *four(){}
virtual char five(){}
virtual char *nine(){}
virtual int multiplier(){}
private:
RNInterpreter *thousands;
RNInterpreter *hundreds;
RNInterpreter *tens;
RNInterpreter *ones;
};
class Thousand: public RNInterpreter
{
public:
// provide 1-arg ctor to avoid infinite loop in base class ctor
Thousand(int): RNInterpreter(1){}
protected:
char one()
{
return 'M';
}
char *four()
{
return "";
}
char five()
{
return '\0';
}
char *nine()
{
return "";
}
int multiplier()
{
return 1000;
}
};
class Hundred: public RNInterpreter
{
public:
Behaioral patterns 15) of 205
Hundred(int): RNInterpreter(1){}
protected:
char one()
{
return 'C';
}
char *four()
{
return "CD";
}
char five()
{
return 'D';
}
char *nine()
{
return "CM";
}
int multiplier()
{
return 100;
}
};
class Ten: public RNInterpreter
{
public:
Ten(int): RNInterpreter(1){}
protected:
char one()
{
return 'X';
}
char *four()
{
return "XL";
}
char five()
{
return 'L';
}
char *nine()
{
return "XC";
}
int multiplier()
{
return 10;
}
};
class One: public RNInterpreter
{
public:
One(int): RNInterpreter(1){}
protected:
Behaioral patterns 155 of 205
char one()
{
return 'I';
}
char *four()
{
return "IV";
}
char five()
{
return 'V';
}
char *nine()
{
return "IX";
}
int multiplier()
{
return 1;
}
};
RNInterpreter::RNInterpreter()
{
// use 1-arg ctor to avoid infinite loop
thousands = new Thousand(1);
hundreds = new Hundred(1);
tens = new Ten(1);
ones = new One(1);
}
int RNInterpreter::interpret(char *input)
{
int total;
total = 0;
thousands->interpret(input, total);
hundreds->interpret(input, total);
tens->interpret(input, total);
ones->interpret(input, total);
if (strcmp(input, ""))
// if input was invalid, return 0
return 0;
return total;
}
int main()
{
RNInterpreter interpreter;
char input[20];
cout << "Enter Roman Numeral: ";
while (cin >> input)
{
cout << " interpretation is " << interpreter.interpret(input) << endl;
cout << "Enter Roman Numeral: ";
}
}
Behaioral patterns 151 of 205
Enter Roman Numeral: MCMXCVI
interpretation is 1996
Enter Roman Numeral: MMMCMXCIX
interpretation is 3999
Enter Roman Numeral: MMMM
interpretation is 0
Enter Roman Numeral: MDCLXVIIII
interpretation is 0
Enter Roman Numeral: CXCX
interpretation is 0
Enter Roman Numeral: MDCLXVI
interpretation is 1666
Enter Roman Numeral: DCCCLXXXVIII
interpretation is 888
Interpreter in 8aa7 Before and after
Before
*his is an adaptation of a design that appeared in a 'ascal data structures book. *he intent +as
to use stacks to convert normal Jinfi2K synta2 into Jpostfi2K notation +ith operator precedence
already handled.
public class InterpreterDemo
{
public static boolean precedence(char a, char b)
{
String high = "*/", low = "+-";
if (a == '(')
return false;
if (a == ')' && b == '(')
{
System.out.println(")-(");
return false;
}
if (b == '(')
return false;
if (b == ')')
return true;
if (high.indexOf(a) > - 1 && low.indexOf(b) > - 1)
return true;
if (high.indexOf(a) > - 1 && high.indexOf(b) > - 1)
return true;
if (low.indexOf(a) > - 1 && low.indexOf(b) > - 1)
return true;
return false;
}
public static String convert_to_postfix(String expr)
{
Stack < Character > op_stack = new Stack < Character > ();
StringBuffer out = new StringBuffer();
String opers = "+-*/()";
char top_sym = '+';
boolean empty;
String[] tokens = expr.split(" ");
Behaioral patterns 152 of 205
for (int i = 0; i < tokens.length; i++)
if (opers.indexOf(tokens[i].charAt(0)) == - 1)
{
out.append(tokens[i]);
out.append(' ');
}
else
{
while (!(empty = op_stack.isEmpty()) && precedence(top_sym =
op_stack.pop(), tokens[i].charAt(0)))
{
out.append(top_sym);
out.append(' ');
}
if (!empty)
op_stack.push(top_sym);
if (empty || tokens[i].charAt(0) != ')')
op_stack.push(tokens[i].charAt(0));
else
top_sym = op_stack.pop();
}
while (!op_stack.isEmpty())
{
out.append(op_stack.pop());
out.append(' ');
}
return out.toString();
}
public static double process_postfix(String postfix, HashMap < String,
Integer > map)
{
Stack < Double > stack = new Stack < Double > ();
String opers = "+-*/";
String[] tokens = postfix.split(" ");
for (int i = 0; i < tokens.length; i++)
// If token is a number or variable
if (opers.indexOf(tokens[i].charAt(0)) == - 1)
{
double term = 0.;
try
{
term = Double.parseDouble(tokens[i]);
}
catch (NumberFormatException ex)
{
term = map.get(tokens[i]);
}
stack.push(term);
// If token is an operator
}
else
{
double b = stack.pop(), a = stack.pop();
if (tokens[i].charAt(0) == '+')
a = a + b;
Behaioral patterns 158 of 205
else if (tokens[i].charAt(0) == '-')
a = a - b;
else if (tokens[i].charAt(0) == '*')
a = a * b;
else if (tokens[i].charAt(0) == '/')
a = a / b;
stack.push(a);
}
return stack.pop();
}
public static void main(String[] args)
{
String infix = "C * 9 / 5 + 32";
String postfix = convert_to_postfix(infix);
System.out.println("Infix: " + infix);
System.out.println("Postfix: " + postfix);
HashMap < String, Integer > map = new HashMap < String, Integer > ();
for (int i = 0; i <= 100; i += 10)
{
map.put("C", i);
System.out.println("C is " + i + ", F is " + process_postfix
(postfix, map));
}
}
}
Infix: C * 9 / 5 + 32
Postfix: C 9 * 5 / 32 +
C is 0, F is 32.0
C is 10, F is 50.0
C is 20, F is 68.0
C is 30, F is 86.0
C is 40, F is 104.0
C is 50, F is 122.0
C is 60, F is 140.0
C is 70, F is 158.0
C is 80, F is 176.0
C is 90, F is 194.0
C is 100, F is 212.0
#fter
*his is a refactoring that follo+s the intent of the -nterpreter design pattern. All classes in the
7perand hierarchy: implement the evaluateEconte2tG! digest some piece of the conte2t argument!
and return their contribution to the recursive traversal. Applying the -nterpreter pattern in this
domain is probably inappropriate.
interface Operand
{
double evaluate(HashMap < String, Integer > context);
void traverse(int level);
}
class Expression implements Operand
{
private char m_operator;
Behaioral patterns 154 of 205
public Operand left, rite;
public Expression(char op)
{
m_operator = op;
}
public void traverse(int level)
{
left.traverse(level + 1);
System.out.print("" + level + m_operator + level + " ");
rite.traverse(level + 1);
}
public double evaluate(HashMap < String, Integer > context)
{
double result = 0.;
double a = left.evaluate(context);
double b = rite.evaluate(context);
if (m_operator == '+')
result = a + b;
else if (m_operator == '-')
result = a - b;
else if (m_operator == '*')
result = a * b;
else if (m_operator == '/')
result = a / b;
return result;
}
}
class Variable implements Operand
{
private String m_name;
public Variable(String name)
{
m_name = name;
}
public void traverse(int level)
{
System.out.print(m_name + " ");
}
public double evaluate(HashMap < String, Integer > context)
{
return context.get(m_name);
}
}
class Number implements Operand
{
private double m_value;
public Number(double value)
{
m_value = value;
}
public void traverse(int level)
{
System.out.print(m_value + " ");
}
Behaioral patterns 110 of 205
public double evaluate(HashMap context)
{
return m_value;
}
}
public class InterpreterDemo
{
public static boolean precedence(char a, char b)
{
String high = "*/", low = "+-";
if (a == '(')
return false;
if (a == ')' && b == '(')
{
System.out.println(")-(");
return false;
}
if (b == '(')
return false;
if (b == ')')
return true;
if (high.indexOf(a) > - 1 && low.indexOf(b) > - 1)
return true;
if (high.indexOf(a) > - 1 && high.indexOf(b) > - 1)
return true;
if (low.indexOf(a) > - 1 && low.indexOf(b) > - 1)
return true;
return false;
}
public static String convert_to_postfix(String expr)
{
Stack < Character > op_stack = new Stack < Character > ();
StringBuffer out = new StringBuffer();
String opers = "+-*/()";
char top_sym = '+';
boolean empty;
String[] tokens = expr.split(" ");
for (int i = 0; i < tokens.length; i++)
if (opers.indexOf(tokens[i].charAt(0)) == - 1)
{
out.append(tokens[i]);
out.append(' ');
}
else
{
while (!(empty = op_stack.isEmpty()) && precedence(top_sym =
op_stack.pop(), tokens[i].charAt(0)))
{
out.append(top_sym);
out.append(' ');
}
if (!empty)
op_stack.push(top_sym);
if (empty || tokens[i].charAt(0) != ')')
Behaioral patterns 111 of 205
op_stack.push(tokens[i].charAt(0));
else
top_sym = op_stack.pop();
}
while (!op_stack.isEmpty())
{
out.append(op_stack.pop());
out.append(' ');
}
return out.toString();
}
public static Operand build_syntax_tree(String tree)
{
Stack < Operand > stack = new Stack < Operand > ();
String opers = "+-*/";
String[] tokens = tree.split(" ");
for (int i = 0; i < tokens.length; i++)
// If token is a number or variable
if (opers.indexOf(tokens[i].charAt(0)) == - 1)
{
Operand term = null;
try
{
term = new Number(Double.parseDouble(tokens[i]));
}
catch (NumberFormatException ex)
{
term = new Variable(tokens[i]);
}
stack.push(term);
// If token is an operator
}
else
{
Expression expr = new Expression(tokens[i].charAt(0));
expr.rite = stack.pop();
expr.left = stack.pop();
stack.push(expr);
}
return stack.pop();
}
public static void main(String[] args)
{
System.out.println("celsi * 9 / 5 + thirty");
String postfix = convert_to_postfix("celsi * 9 / 5 + thirty");
System.out.println(postfix);
Operand expr = build_syntax_tree(postfix);
expr.traverse(1);
System.out.println();
HashMap < String, Integer > map = new HashMap < String, Integer > ();
map.put("thirty", 30);
for (int i = 0; i <= 100; i += 10)
{
map.put("celsi", i);
System.out.println("C is " + i + ", F is " + expr.evaluate(map));
Behaioral patterns 112 of 205
}
}
}
celsi * 9 / 5 + thirty
celsi 9 * 5 / thirty +
celsi 3*3 9.0 2/2 5.0 1+1 thirty
C is 0, F is 30.0
C is 10, F is 48.0
C is 20, F is 66.0
C is 30, F is 84.0
C is 40, F is 102.0
C is 50, F is 120.0
C is 60, F is 138.0
C is 70, F is 156.0
C is 80, F is 174.0
C is 90, F is 192.0
C is 100, F is 210.0
Interpreter in 8aa
Interpreter aside
The pattern doesnt address parsing.
When the grammer is very complex, other techniques (such as a parser) are more appropriate.
public class InterpreterDemo {
public static boolean precedence( char a, char b ) {
String high = "*/", low = "+-";
if (a == '(') return false; // if (a == '(' && b == ')') return false;
if (a == ')' && b == '(') { System.out.println( ")-(" ); return false; }
if (b == '(') return false;
if (b == ')') return true;
if (high.indexOf( a ) > -1 && low.indexOf( b ) > -1) return true;
if (high.indexOf( a ) > -1 && high.indexOf( b ) > -1) return true;
if (low.indexOf( a ) > -1 && low.indexOf( b ) > -1) return true;
return false;
}
public static String convertToPostfix( String in ) {
StkChar opstk = new StkChar();
StringBuffer out = new StringBuffer();
String opers = "+-*/()";
char topsym = '+';
boolean empty;
for (int i = 0; i < in.length(); i++)
if (opers.indexOf( in.charAt(i) ) == -1)
out.append( in.charAt(i) );
else {
while ( ! (empty = opstk.isEmpty())
&& precedence( topsym = opstk.pop(), in.charAt(i) ))
out.append( topsym );
if ( ! empty) opstk.push( topsym );
if (empty || in.charAt(i) != ')') opstk.push( in.charAt(i) );
else topsym = opstk.pop();
}
Behaioral patterns 11! of 205
while ( ! opstk.isEmpty()) out.append( opstk.pop() );
return out.toString();
}
public static int evaluate( String in ) {
StkInt stack = new StkInt();
String opers = "+-*/";
for (int a, b, i=0; i < in.length(); i++)
if (opers.indexOf( in.charAt(i) ) == -1)
stack.push( in.charAt(i)-48 );
else {
b = stack.pop(); a = stack.pop();
if (in.charAt(i) == '+') a = a + b;
else if (in.charAt(i) == '-') a = a - b;
else if (in.charAt(i) == '*') a = a * b;
else if (in.charAt(i) == '/') a = a / b;
stack.push( a );
}
return stack.pop();
}
public static void main( String[] args ) {
System.out.print( args[0] );
String postfix = convertToPostfix( args[0] );
System.out.print( " -- " + postfix );
System.out.println( " -- " + evaluate( postfix ) );
}
class StkChar {
private char[] arr = new char[9];
private int sp = -1;
void push( char ch ) { if ( ! isFull()) arr[++sp] = ch; }
char pop() { if (isEmpty()) return '\0'; return arr[sp--]; }
boolean isFull() { return sp == arr.length-1; }
boolean isEmpty() { return sp == -1; }
}
class StkInt {
private int[] arr = new int[9];
private int sp = -1;
void push( int ch ) { if ( ! isFull()) arr[++sp] = ch; }
int pop() { if (isEmpty()) return 0; return arr[sp--]; }
boolean isFull() { return sp == arr.length-1; }
boolean isEmpty() { return sp == -1; }
}}
2+3*4-5+6 -- 234*+5-6+ -- 15
(2+3)*4-5+6 -- 23+4*5-6+ -- 21
2+3*(4-5)+6 -- 2345-*+6+ -- 5
2+3*((4-5)+6) -- 2345-6+*+ -- 17
(3-(4*(5+6))/(7-8))*9/4 -- 3456+*78-/-9*4/ -- 105
Iterator Design Pattern
Intent
'rovide a +ay to access the elements of an aggregate ob8ect se=uentially +ithout e2posing
Behaioral patterns 11) of 205
its underlying representation.
*he (FF and Mava standard library abstraction that makes it possible to decouple
collection classes and algorithms.
'romote to Jfull ob8ect statusK the traversal of a collection.
'olymorphic traversal
Proble*
Need to JabstractK the traversal of +ildly different data structures so that algorithms can be
defined that are capable of interfacing +ith each transparently.
Discussion
JAn aggregate ob8ect such as a list should give you a +ay to access its elements +ithout e2posing
its internal structure. Moreover! you might +ant to traverse the list in different +ays! depending
on +hat you need to accomplish. 6ut you probably donAt +ant to bloat the ,ist interface +ith
operations for different traversals! even if you could anticipate the ones youAll re=uire. Uou might
also need to have more than one traversal pending on the same list.K And! providing a uniform
interface for traversing many types of aggregate ob8ects Ei.e. polymorphic iterationG might be
valuable.
*he -terator pattern lets you do all this. *he key idea is to take the responsibility for access and
traversal out of the aggregate ob8ect and put it into an -terator ob8ect that defines a standard
traversal protocol.
*he -terator abstraction is fundamental to an emerging technology called Jgeneric
programmingK. *his strategy seeks to e2plicitly separate the notion of JalgorithmK from that of
Jdata structureK. *he motivation is to: promote component>based development! boost
productivity! and reduce configuration management.
As an e2ample! if you +anted to support four data structures Earray! binary tree! linked list! and
hash tableG and three algorithms Esort! find! and mergeG! a traditional approach +ould re=uire
four times three permutations to develop and maintain. ?hereas! a generic programming
approach +ould only re=uire four plus three configuration items.
Structure
*he (lient uses the (ollection classA public interface directly. 6ut access to the (ollectionAs
elements is encapsulated behind the additional level of abstraction called -terator. 1ach
(ollection derived class kno+s +hich -terator derived class to create and return. After that! the
(lient relies on the interface defined in the -terator base class.
Behaioral patterns 115 of 205
5,a*ple
*he -terator provides +ays to access elements of an aggregate ob8ect se=uentially +ithout
e2posing the underlying structure of the ob8ect. /iles are aggregate ob8ects. -n office settings
+here access to files is made through administrative or secretarial staff! the -terator pattern is
demonstrated +ith the secretary acting as the -terator. everal television comedy skits have been
developed around the premise of an e2ecutive trying to understand the secretaryAs filing system.
*o the e2ecutive! the filing system is confusing and illogical! but the secretary is able to access
files =uickly and efficiently.
7n early television sets! a dial +as used to change channels. ?hen channel surfing! the vie+er
+as re=uired to move the dial through each channel position! regardless of +hether or not that
channel had reception. 7n modern television sets! a ne2t and previous button are used. ?hen the
vie+er selects the Jne2tK button! the ne2t tuned channel +ill be displayed. (onsider +atching
television in a hotel room in a strange city. ?hen surfing through channels! the channel number
is not important! but the programming is. -f the programming on one channel is not of interest!
the vie+er can re=uest the ne2t channel! +ithout kno+ing its number.
Chec0 list
$. Add a create_iteratorEG method to the JcollectionK class! and grant the JiteratorK class
privileged access.
". &esign an JiteratorK class that can encapsulate traversal of the JcollectionK class.
). (lients ask the collection ob8ect to create an iterator ob8ect.
9. (lients use the firstEG! is_doneEG! ne2tEG! and current_itemEG protocol to access the elements
of the collection class.
3ules of thu*b
*he abstract synta2 tree of -nterpreter is a (omposite Etherefore -terator and ;isitor are
also applicableG.
-terator can traverse a (omposite. ;isitor can apply an operation over a (omposite.
'olymorphic -terators rely on /actory Methods to instantiate the appropriate -terator
subclass.
Memento is often used in con8unction +ith -terator. An -terator can use a Memento to
Behaioral patterns 111 of 205
capture the state of an iteration. *he -terator stores the Memento internally.
Iterator in C66
Iterator design pattern
*ake traversal>of>a>collection functionality out of the collection and promote it to Jfull ob8ect
statusK. *his simplifies the collection! allo+s many traversals to be active simultaneously! and
decouples collection algo> rithms from collection data structures.
J1very Vcontainer>likeA class must have an iterator.K -t may seem like a violation of encapsulation
for a tack class to allo+ its users to access its contents directly! but Mohn ,akosA argument is
that the designer of a class inevitably leaves something out. ,ater! +hen users need addi> tional
functionality! if an iterator +as originally provided! they can add functionality +ith Jopen for
e2tension! closed for modificationK. ?ithout an iterator! their only recourse is to invasively
customi@e production code. 6elo+! the orginal tack class did not include an e=uality operator!
but it did include an iterator. As a result! the e=uality operator could be readily retrofitted.
$. &esign an JiteratorK class for the JcontainerK class
". Add a create-teratorEG member to the container class
). (lients ask the container ob8ect to create an iterator ob8ect
9. (lients use the firstEG! is&oneEG! ne2tEG! and current-temEG protocol
#include <iostream>
using namespace std;
class Stack
{
int items[10];
int sp;
public:
friend class StackIter;
Stack()
{
sp = - 1;
}
void push(int in)
{
items[++sp] = in;
}
int pop()
{
return items[sp--];
}
bool isEmpty()
{
return (sp == - 1);
}
StackIter *createIterator()const; // 2. Add a createIterator() member
};
class StackIter
{
// 1. Design an "iterator" class
const Stack *stk;
Behaioral patterns 112 of 205
int index;
public:
StackIter(const Stack *s)
{
stk = s;
}
void first()
{
index = 0;
}
void next()
{
index++;
}
bool isDone()
{
return index == stk->sp + 1;
}
int currentItem()
{
return stk->items[index];
}
};
StackIter *Stack::createIterator()const
{
return new StackIter(this);
}
bool operator == (const Stack &l, const Stack &r)
{
// 3. Clients ask the container object to create an iterator object
StackIter *itl = l.createIterator();
StackIter *itr = r.createIterator();
// 4. Clients use the first(), isDone(), next(), and currentItem() protocol
for (itl->first(), itr->first(); !itl->isDone(); itl->next(), itr->next())
if (itl->currentItem() != itr->currentItem())
break;
bool ans = itl->isDone() && itr->isDone();
delete itl;
delete itr;
return ans;
}
int main()
{
Stack s1;
for (int i = 1; i < 5; i++)
s1.push(i);
Stack s2(s1), s3(s1), s4(s1), s5(s1);
s3.pop();
s5.pop();
s4.push(2);
s5.push(9);
cout << "1 == 2 is " << (s1 == s2) << endl;
cout << "1 == 3 is " << (s1 == s3) << endl;
Behaioral patterns 118 of 205
cout << "1 == 4 is " << (s1 == s4) << endl;
cout << "1 == 5 is " << (s1 == s5) << endl;
}
1 == 2 is 1
1 == 3 is 0
1 == 4 is 0
1 == 5 is 0
Iterator in C667 "sing operators instead of *ethods
&iscussion. Mohn ,akos suggests the C7/ and *, iterator interfaces are: error>prone Epossibility
of misspelling method namesG! clumsy! and re=uire too much typing. *his design uses nothing but
JintuitiveK operators. Notice also that no create-teratorEG +as specified. *he user creates these
iterators as local variables! and no clean>up is necessary.
#include <iostream>
using namespace std;
class Stack
{
int items[10];
int sp;
public:
friend class StackIter;
Stack()
{
sp = - 1;
}
void push(int in)
{
items[++sp] = in;
}
int pop()
{
return items[sp--];
}
bool isEmpty()
{
return (sp == - 1);
}
};
class StackIter
{
const Stack &stk;
int index;
public:
StackIter(const Stack &s): stk(s)
{
index = 0;
}
void operator++()
{
index++;
}
Behaioral patterns 114 of 205
bool operator()()
{
return index != stk.sp + 1;
}
int operator *()
{
return stk.items[index];
}
};
bool operator == (const Stack &l, const Stack &r)
{
StackIter itl(l), itr(r);
for (; itl(); ++itl, ++itr)
if (*itl != *itr)
break;
return !itl() && !itr();
}
int main()
{
Stack s1;
int i;
for (i = 1; i < 5; i++)
s1.push(i);
Stack s2(s1), s3(s1), s4(s1), s5(s1);
s3.pop();
s5.pop();
s4.push(2);
s5.push(9);
cout << "1 == 2 is " << (s1 == s2) << endl;
cout << "1 == 3 is " << (s1 == s3) << endl;
cout << "1 == 4 is " << (s1 == s4) << endl;
cout << "1 == 5 is " << (s1 == s5) << endl;
}
1 == 2 is 1
1 == 3 is 0
1 == 4 is 0
1 == 5 is 0
Iterator in 8aa7 Before and after
*he class ome(lass?ith&ata provides access to its internal data structure. (lients can
accidently or maliciously trash that data structure.
class SomeClassWithData
{
private TreeSet < Integer > m_data = new TreeSet < Integer > ();
public void add(int in)
{
m_data.add(in);
}
public Collection get_data()
{
Behaioral patterns 120 of 205
return m_data;
}
}
class IteratorDemo
{
public static void main(String[] args)
{
SomeClassWithData some_object = new SomeClassWithData();
for (int i = 9; i > 0; --i)
some_object.add(i);
Collection data = some_object.get_data();
for (java.util.Iterator it = data.iterator(); it.hasNext();)
System.out.print(it.next() + " ");
System.out.println();
// Do we really want a client to be able to
// trash encapsulated state?
data.clear();
data = some_object.get_data();
System.out.println("size of data is " + data.size());
}
}
1 2 3 4 5 6 7 8 9
size of data is 0
#fter
*ake traversal>of>a>collection functionality out of the collection and promote it to Jfull ob8ect
statusK. *his simplifies the collection! allo+s many traversals to be active simultaneously! and
decouples collection algorithms from collection data structures.
class SomeClassWithData
{
private TreeSet < Integer > m_data = new TreeSet < Integer > ();
public class Iterator
{
private SomeClassWithData m_collection;
private java.util.Iterator m_it;
private int m_current;
public Iterator(SomeClassWithData in)
{
m_collection = in;
}
public void first()
{
m_it = m_collection.m_data.iterator();
next();
}
public void next()
{
try
{
m_current = m_it.next();
}
Behaioral patterns 121 of 205
catch (NoSuchElementException ex)
{
m_current = - 999;
}
}
public boolean is_done()
{
return m_current == - 999;
}
public int current_item()
{
return m_current;
}
}
public void add(int in)
{
m_data.add(in);
}
public Iterator create_iterator()
{
return new Iterator(this);
}
}
class IteratorDemo
{
public static void main(String[] args)
{
SomeClassWithData some_object = new SomeClassWithData();
for (int i = 9; i > 0; --i)
some_object.add(i);
// get_data() has been removed.
// Client has to use Iterator.
SomeClassWithData.Iterator it1 = some_object.create_iterator();
SomeClassWithData.Iterator it2 = some_object.create_iterator();
for (it1.first(); !it1.is_done(); it1.next())
System.out.print(it1.current_item() + " ");
System.out.println();
// Two simultaneous iterations
for (it1.first(), it2.first(); !it1.is_done(); it1.next(), it2.next())
System.out.print(it1.current_item() + " " + it2.current_item() + " ")
;
System.out.println();
}
}
1 2 3 4 5 6 7 8 9
1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
Behaioral patterns 122 of 205
Iterator in 8aa
Iterator design pattern
*ake traversal>of>a>collection functionality out of the collection and promote it to Jfull ob8ect
statusK. *his simplifies the collection! allo+s many traversals to be active simultaneously! and
decouples collection algo> rithms from collection data structures.
$. &esign an internal JiteratorK class for the JcollectionK class
". Add a create-teratorEG member to the collection class
). (lients ask the collection ob8ect to create an iterator ob8ect
9. (lients use the firstEG! is&oneEG! ne2tEG! and current-temEG protocol
import java.util.*;
class IntSet {
private Hashtable ht = new Hashtable();
// 1. Design an internal "iterator" class for the "collection" class
public static class Iterator {
private IntSet set;
private Enumeration e;
private Integer current;
public Iterator( IntSet in ) { set = in; }
public void first() { e = set.ht.keys(); next(); }
public boolean isDone() { return current == null; }
public int currentItem() { return current.intValue(); }
public void next() {
try { current = (Integer) e.nextElement(); }
catch (NoSuchElementException e) { current = null; }
} }
public void add( int in ) { ht.put( new Integer( in ), "null" ); }
public boolean isMember( int i ) { return ht.containsKey(new Integer(i)); }
public Hashtable getHashtable() { return ht; }
// 2. Add a createIterator() member to the collection class
public Iterator createIterator() { return new Iterator( this ); }
}
class IteratorDemo {
public static void main( String[] args ) {
IntSet set = new IntSet();
for (int i=2; i < 10; i += 2) set.add( i );
for (int i=1; i < 9; i++)
System.out.print( i + "-" + set.isMember( i ) + " " );
// 3. Clients ask the collection object to create many iterator objects
IntSet.Iterator it1 = set.createIterator();
IntSet.Iterator it2 = set.createIterator();
// 4. Clients use the first(), isDone(), next(), currentItem() protocol
System.out.print( "\nIterator: " );
for ( it1.first(), it2.first(); ! it1.isDone(); it1.next(), it2.next() )
System.out.print( it1.currentItem() + " " + it2.currentItem() + " " );
Behaioral patterns 12! of 205
// Java uses a different collection traversal "idiom" called Enumeration
System.out.print( "\nEnumeration: " );
for (Enumeration e = set.getHashtable().keys(); e.hasMoreElements(); )
System.out.print( e.nextElement() + " " );
System.out.println();
} }
1-false 2-true 3-false 4-true 5-false 6-true 7-false 8-true
Iterator: 8 8 6 6 4 4 2 2
Enumeration: 8 6 4 2
&ediator Design Pattern
Intent
&efine an ob8ect that encapsulates ho+ a set of ob8ects interact. Mediator promotes loose
coupling by keeping ob8ects from referring to each other e2plicitly! and it lets you vary
their interaction independently.
&esign an intermediary to decouple many peers.
'romote the many>to>many relationships bet+een interacting peers to Jfull ob8ect statusK.
Proble*
?e +ant to design reusable components! but dependencies bet+een the potentially reusable
pieces demonstrates the Jspaghetti codeK phenomenon Etrying to scoop a single serving results in
an Jall or nothing clumpKG.
Discussion
-n %ni2! permission to access system resources is managed at three levels of granularity: +orld!
group! and o+ner. A group is a collection of users intended to model some functional affiliation.
1ach user on the system can be a member of one or more groups! and each group can have @ero
or more users assigned to it. Ne2t figure sho+s three users that are assigned to all three groups.
Behaioral patterns 12) of 205
-f +e +ere to model this in soft+are! +e could decide to have %ser ob8ects coupled to Croup
ob8ects! and Croup ob8ects coupled to %ser ob8ects. *hen +hen changes occur! both classes and
all their instances +ould be affected.
An alternate approach +ould be to introduce Jan additional level of indirectionK > take the
mapping of users to groups and groups to users! and make it an abstraction unto itself. *his
offers several advantages: %sers and Croups are decoupled from one another! many mappings
can easily be maintained and manipulated simultaneously! and the mapping abstraction can be
e2tended in the future by defining derived classes.
'artitioning a system into
many ob8ects generally enhances reusability! but proliferating interconnections bet+een those
ob8ects tend to reduce it again. *he mediator ob8ect: encapsulates all interconnections! acts as
the hub of communication! is responsible for controlling and coordinating the interactions of its
clients! and promotes loose coupling by keeping ob8ects from referring to each other e2plicitly.
*he Mediator pattern promotes a Jmany>to>many relationship net+orkK to Jfull ob8ect statusK.
Modelling the inter>relationships +ith an ob8ect enhances encapsulation! and allo+s the behavior
of those inter>relationships to be modified or e2tended through subclassing.
An e2ample +here Mediator is useful is the design of a user and group capability in an operating
system. A group can have @ero or more users! and! a user can be a member of @ero or more
groups. *he Mediator pattern provides a fle2ible and non>invasive +ay to associate and manage
users and groups.
Structure
(olleagues Eor peersG are not coupled to one another. 1ach talks to the Mediator! +hich in turn
kno+s and conducts the orchestration of the others. *he Jmany to manyK mapping bet+een
colleagues that +ould other+ise e2ist! has been Jpromoted to full ob8ect statusK. *his ne+
Behaioral patterns 125 of 205
abstraction provides a locus of indirection +here additional leverage can be hosted.
5,a*ple
*he Mediator defines an ob8ect that controls ho+ a set of ob8ects interact. ,oose coupling
bet+een colleague ob8ects is achieved by having colleagues communicate +ith the Mediator!
rather than +ith each other. *he control to+er at a controlled airport demonstrates this pattern
very +ell. *he pilots of the planes approaching or departing the terminal area communicate +ith
the to+er rather than e2plicitly communicating +ith one another. *he constraints on +ho can
take off or land are enforced by the to+er. -t is important to note that the to+er does not control
the +hole flight. -t e2ists only to enforce constraints in the terminal area.
Chec0 list
$. -dentify a collection of interacting ob8ects that +ould benefit from mutual decoupling.
". 1ncapsulate those interactions in the abstraction of a ne+ class.
). (reate an instance of that ne+ class and re+ork all JpeerK ob8ects to interact +ith the
Mediator only.
9. 6alance the principle of decoupling +ith the principle of distributing responsibility evenly.
.. 6e careful not to create a JcontrollerK or JgodK ob8ect.
3ules of thu*b
Behaioral patterns 121 of 205
(hain of 5esponsibility! (ommand! Mediator! and 7bserver! address ho+ you can decouple
senders and receivers! but +ith different trade>offs. (hain of 5esponsibility passes a
sender re=uest along a chain of potential receivers. (ommand normally specifies a sender>
receiver connection +ith a subclass. Mediator has senders and receivers reference each
other indirectly. 7bserver defines a very decoupled interface that allo+s for multiple
receivers to be configured at run>time.
Mediator and 7bserver are competing patterns. *he difference bet+een them is that
7bserver distributes communication by introducing JobserverK and Jsub8ectK ob8ects!
+hereas a Mediator ob8ect encapsulates the communication bet+een other ob8ects. ?eAve
found it easier to make reusable 7bservers and ub8ects than to make reusable
Mediators.
7n the other hand! Mediator can leverage 7bserver for dynamically registering colleagues
and communicating +ith them.
Mediator is similar to /acade in that it abstracts functionality of e2isting classes. Mediator
abstracts/centrali@es arbitrary communication bet+een colleague ob8ects! it routinely
Jadds valueK! and it is kno+n/referenced by the colleague ob8ects Ei.e. it defines a
multidirectional protocolG. -n contrast! /acade defines a simpler interface to a subsystem!
it doesnAt add ne+ functionality! and it is not kno+n by the subsystem classes Ei.e. it
defines a unidirectional protocol +here it makes re=uests of the subsystem classes but not
vice versaG.
&ediator in C667 Before and after
Before
Node ob8ects interact directly +ith each other! recursion is re=uired! removing a Node is hard!
and it is not possible to remove the first node.
class Node
{
public:
Node(int v)
{
m_val = v;
m_next = 0;
}
void add_node(Node *n)
{
if (m_next)
m_next->add_node(n);
else
m_next = n;
}
void traverse()
{
cout << m_val << " ";
if (m_next)
m_next->traverse();
else
cout << '\n';
}
void remove_node(int v)
{
Behaioral patterns 122 of 205
if (m_next)
if (m_next->m_val == v)
m_next = m_next->m_next;
else
m_next->remove_node(v);
}
private:
int m_val;
Node *m_next;
};
int main()
{
Node lst(11);
Node two(22), thr(33), fou(44);
lst.add_node(&two);
lst.add_node(&thr);
lst.add_node(&fou);
lst.traverse();
lst.remove_node(44);
lst.traverse();
lst.remove_node(22);
lst.traverse();
lst.remove_node(11);
lst.traverse();
}
11 22 33 44
11 22 33
11 33
11 33
#fter
A JmediatingK ,ist class focuses and simplifies all the administrative responsibilities! and the
recursion E+hich does not scale up +ellG has been eliminated.
class Node
{
public:
Node(int v)
{
m_val = v;
}
int get_val()
{
return m_val;
}
private:
int m_val;
};
class List
{
public:
void add_node(Node *n)
Behaioral patterns 128 of 205
{
m_arr.push_back(n);
}
void traverse()
{
for (int i = 0; i < m_arr.size(); ++i)
cout << m_arr[i]->get_val() << " ";
cout << '\n';
}
void remove_node(int v)
{
for (vector::iterator it = m_arr.begin(); it != m_arr.end(); ++it)
if ((*it)->get_val() == v)
{
m_arr.erase(it);
break;
}
}
private:
vector m_arr;
};
int main()
{
List lst;
Node one(11), two(22);
Node thr(33), fou(44);
lst.add_node(&one);
lst.add_node(&two);
lst.add_node(&thr);
lst.add_node(&fou);
lst.traverse();
lst.remove_node(44);
lst.traverse();
lst.remove_node(22);
lst.traverse();
lst.remove_node(11);
lst.traverse();
}
11 22 33 44
11 22 33
11 33
33
&ediator in C66
&ediator design pattern de*o
&iscussion. *hough partitioning a system into many ob8ects generally enhances reusability!
proliferating interconnections tend to reduce it again. Uou can avoid this problem by capsulating
the interconnections Ei.e. the collective behaviorG in a separate JmediatorK ob8ect. A mediator is
responsible for controlling and coordinating the interactions of a group of ob8ects.
-n this e2ample! the dialog bo2 ob8ect is functioning as the mediator. (hild +idgets of the dialog
bo2 do not kno+! or care! +ho their siblings are. ?henever a simulated user interaction occurs in
Behaioral patterns 124 of 205
a child +idget ?idget::changedEG! the +idget does nothing e2cept JdelegateK that event to its
parent dialog bo2 mediator>\+idget(hangedEthisG.
/ileelection&ialog::+idget(hangedEG encapsulates all collective behavior for the dialog bo2 Eit
serves as the hub of communicationG. *he user may choose to JinteractK +ith a simulated: filter
edit field! directories list! files list! or selection edit field.
#include <iostream.h>
class FileSelectionDialog;
class Widget
{
public:
Widget(FileSelectionDialog *mediator, char *name)
{
_mediator = mediator;
strcpy(_name, name);
}
virtual void changed();
virtual void updateWidget() = 0;
virtual void queryWidget() = 0;
protected:
char _name[20];
private:
FileSelectionDialog *_mediator;
};
class List: public Widget
{
public:
List(FileSelectionDialog *dir, char *name): Widget(dir, name){}
void queryWidget()
{
cout << " " << _name << " list queried" << endl;
}
void updateWidget()
{
cout << " " << _name << " list updated" << endl;
}
};
class Edit: public Widget
{
public:
Edit(FileSelectionDialog *dir, char *name): Widget(dir, name){}
void queryWidget()
{
cout << " " << _name << " edit queried" << endl;
}
void updateWidget()
{
cout << " " << _name << " edit updated" << endl;
}
};
class FileSelectionDialog
Behaioral patterns 180 of 205
{
public:
enum Widgets
{
FilterEdit, DirList, FileList, SelectionEdit
};
FileSelectionDialog()
{
_components[FilterEdit] = new Edit(this, "filter");
_components[DirList] = new List(this, "dir");
_components[FileList] = new List(this, "file");
_components[SelectionEdit] = new Edit(this, "selection");
}
virtual ~FileSelectionDialog();
void handleEvent(int which)
{
_components[which]->changed();
}
virtual void widgetChanged(Widget *theChangedWidget)
{
if (theChangedWidget == _components[FilterEdit])
{
_components[FilterEdit]->queryWidget();
_components[DirList]->updateWidget();
_components[FileList]->updateWidget();
_components[SelectionEdit]->updateWidget();
}
else if (theChangedWidget == _components[DirList])
{
_components[DirList]->queryWidget();
_components[FileList]->updateWidget();
_components[FilterEdit]->updateWidget();
_components[SelectionEdit]->updateWidget();
}
else if (theChangedWidget == _components[FileList])
{
_components[FileList]->queryWidget();
_components[SelectionEdit]->updateWidget();
}
else if (theChangedWidget == _components[SelectionEdit])
{
_components[SelectionEdit]->queryWidget();
cout << " file opened" << endl;
}
}
private:
Widget *_components[4];
};
FileSelectionDialog::~FileSelectionDialog()
{
for (int i = 0; i < 3; i++)
delete _components[i];
}
void Widget::changed()
Behaioral patterns 181 of 205
{
_mediator->widgetChanged(this);
}
int main()
{
FileSelectionDialog fileDialog;
int i;
cout << "Exit[0], Filter[1], Dir[2], File[3], Selection[4]: ";
cin >> i;
while (i)
{
fileDialog.handleEvent(i - 1);
cout << "Exit[0], Filter[1], Dir[2], File[3], Selection[4]: ";
cin >> i;
}
}
Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 1
filter edit queried
dir list updated
file list updated
selection edit updated
Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 2
dir list queried
file list updated
filter edit updated
selection edit updated
Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 3
file list queried
selection edit updated
Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 4
selection edit queried
file opened
Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 3
file list queried
selection edit updated
&ediator in 8aa
&ediator design pattern
$. (reate an JintermediaryK that decouples JsendersK from JreceiversK
". 'roducers are coupled only to the Mediator
). (onsumers are coupled only to the Mediator
Behaioral patterns 182 of 205
9. *he Mediator arbitrates the storing and retrieving of messages
// 1. The "intermediary"
class Mediator {
// 4. The Mediator arbitrates
private boolean slotFull = false;
private int number;
public synchronized void storeMessage( int num ) {
// no room for another message
while (slotFull == true) {
try {
wait();
}
catch (InterruptedException e ) { }
}
slotFull = true;
number = num;
notifyAll();
}
public synchronized int retrieveMessage() {
// no message to retrieve
while (slotFull == false)
try {
wait();
}
catch (InterruptedException e ) { }
slotFull = false;
notifyAll();
return number;
}
}
class Producer extends Thread {
// 2. Producers are coupled only to the Mediator
private Mediator med;
private int id;
private static int num = 1;
public Producer( Mediator m ) {
med = m;
id = num++;
}
public void run() {
int num;
while (true) {
med.storeMessage( num = (int)(Math.random()*100) );
System.out.print( "p" + id + "-" + num + " " );
}
}
}
class Consumer extends Thread {
// 3. Consumers are coupled only to the Mediator
private Mediator med;
private int id;
private static int num = 1;
public Consumer( Mediator m ) {
Behaioral patterns 18! of 205
med = m;
id = num++;
}
public void run() {
while (true) {
System.out.print("c" + id + "-" + med.retrieveMessage() + " ");
}
}
}
class MediatorDemo {
public static void main( String[] args ) {
Mediator mb = new Mediator();
new Producer( mb ).start();
new Producer( mb ).start();
new Consumer( mb ).start();
new Consumer( mb ).start();
new Consumer( mb ).start();
new Consumer( mb ).start();
}
}
p1-87 c1-87 p2-37 c3-37 p1-28 c2-28 p2-58 c1-58 p1-18 c4-18
p2-42 c3-42 p1-3 c2-3 p2-11 c3-11 p1-72 c2-72 p2-75 c3-75
p1-93 c4-93 p2-52 c1-52 p1-21 c3-21 p2-80 c4-80 p1-96 c2-96
&e*ento Design Pattern
Intent
?ithout violating encapsulation! capture and e2ternali@e an ob8ectAs internal state so that
the ob8ect can be returned to this state later.
A magic cookie that encapsulates a Jcheck pointK capability.
'romote undo or rollback to full ob8ect status.
Proble*
Need to restore an ob8ect back to its previous state Ee.g. JundoK or JrollbackK operationsG.
Discussion
*he client re=uests a Memento from the source ob8ect +hen it needs to checkpoint the source
ob8ectAs state. *he source ob8ect initiali@es the Memento +ith a characteri@ation of its state. *he
client is the Jcare>takerK of the Memento! but only the source ob8ect can store and retrieve
information from the Memento Ethe Memento is Jopa=ueK to the client and all other ob8ectsG. -f
the client subse=uently needs to JrollbackK the source ob8ectAs state! it hands the Memento back
to the source ob8ect for reinstatement.
An unlimited JundoK and JredoK capability can be readily implemented +ith a stack of (ommand
ob8ects and a stack of Memento ob8ects.
*he Memento design pattern defines three distinct roles:
$. Originator > the ob8ect that kno+s ho+ to save itself.
Behaioral patterns 18) of 205
". areta!er > the ob8ect that kno+s +hy and +hen the 7riginator needs to save and restore
itself.
). "emento > the lock bo2 that is +ritten and read by the 7riginator! and shepherded by the
(aretaker.
Structure
5,a*ple
*he Memento captures and e2ternali@es an ob8ectAs internal state so that the ob8ect can later be
restored to that state. *his pattern is common among do>it>yourself mechanics repairing drum
brakes on their cars. *he drums are removed from both sides! e2posing both the right and left
brakes. 7nly one side is disassembled and the other serves as a Memento of ho+ the brake parts
fit together. 7nly after the 8ob has been completed on one side is the other side disassembled.
?hen the second side is disassembled! the first side acts as the Memento.
Chec0 list
$. -dentify the roles of JcaretakerK and JoriginatorK.
". (reate a Memento class and declare the originator a friend.
Behaioral patterns 185 of 205
). (aretaker kno+s +hen to Jcheck pointK the originator.
9. 7riginator creates a Memento and copies its state to that Memento.
.. (aretaker holds on to Ebut cannot peek intoG the Memento.
0. (aretaker kno+s +hen to Jroll backK the originator.
3. 7riginator reinstates itself using the saved state in the Memento.
3ules of thu*b
(ommand and Memento act as magic tokens to be passed around and invoked at a later
time. -n (ommand! the token represents a re=uestI in Memento! it represents the internal
state of an ob8ect at a particular time. 'olymorphism is important to (ommand! but not to
Memento because its interface is so narro+ that a memento can only be passed as a value.
(ommand can use Memento to maintain the state re=uired for an undo operation.
Memento is often used in con8unction +ith -terator. An -terator can use a Memento to
capture the state of an iteration. *he -terator stores the Memento internally.
&e*ento in C66
&e*ento design pattern
&iscussion. A memento is an ob8ect that stores a snapshot of the internal state of another ob8ect.
-t can be leveraged to support multi>level undo of the (ommand pattern. -n this e2ample! before
a command is run against the Number ob8ect! NumberAs current state is saved in (ommandAs
static memento history list! and the command itself is saved in the static command history list.
%ndoEG simply JpopsK the memento history list and reinstates NumberAs state from the memento.
5edoEG JpopsK the command history list. Note that NumberAs encapsulation is preserved! and
Memento is +ide open to Number.
#include <iostream.h>
class Number;
class Memento
{
public:
Memento(int val)
{
_state = val;
}
private:
friend class Number; // not essential, but p287 suggests this
int _state;
};
class Number
{
public:
Number(int value)
{
_value = value;
Behaioral patterns 181 of 205
}
void dubble()
{
_value = 2 * _value;
}
void half()
{
_value = _value / 2;
}
int getValue()
{
return _value;
}
Memento *createMemento()
{
return new Memento(_value);
}
void reinstateMemento(Memento *mem)
{
_value = mem->_state;
}
private:
int _value;
};
class Command
{
public:
typedef void(Number:: *Action)();
Command(Number *receiver, Action action)
{
_receiver = receiver;
_action = action;
}
virtual void execute()
{
_mementoList[_numCommands] = _receiver->createMemento();
_commandList[_numCommands] = this;
if (_numCommands > _highWater)
_highWater = _numCommands;
_numCommands++;
(_receiver-> *_action)();
}
static void undo()
{
if (_numCommands == 0)
{
cout << "*** Attempt to run off the end!! ***" << endl;
return ;
}
_commandList[_numCommands - 1]->_receiver->reinstateMemento
(_mementoList[_numCommands - 1]);
_numCommands--;
}
void static redo()
{
Behaioral patterns 182 of 205
if (_numCommands > _highWater)
{
cout << "*** Attempt to run off the end!! ***" << endl;
return ;
}
(_commandList[_numCommands]->_receiver->*(_commandList[_numCommands]
->_action))();
_numCommands++;
}
protected:
Number *_receiver;
Action _action;
static Command *_commandList[20];
static Memento *_mementoList[20];
static int _numCommands;
static int _highWater;
};
Command *Command::_commandList[];
Memento *Command::_mementoList[];
int Command::_numCommands = 0;
int Command::_highWater = 0;
int main()
{
int i;
cout << "Integer: ";
cin >> i;
Number *object = new Number(i);
Command *commands[3];
commands[1] = new Command(object, &Number::dubble);
commands[2] = new Command(object, &Number::half);
cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
cin >> i;
while (i)
{
if (i == 3)
Command::undo();
else if (i == 4)
Command::redo();
else
commands[i]->execute();
cout << " " << object->getValue() << endl;
cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
cin >> i;
}
}
Integer: 11
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
5
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 1
10
Behaioral patterns 188 of 205
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
5
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
10
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
5
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
11
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
*** Attempt to run off the end!! ***
11
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
5
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
10
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
5
Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
*** Attempt to run off the end!! ***
5
&e*ento in 8aa
import java.util.*;
class Memento {
private String state;
public Memento(String stateToSave) { state = stateToSave; }
public String getSavedState() { return state; }
}
class Originator {
private String state;
/* lots of memory consumptive private data that is not necessary to define the
* state and should thus not be saved. Hence the small memento object. */
public void set(String state) {
System.out.println("Originator: Setting state to "+state);
this.state = state;
}
public Memento saveToMemento() {
System.out.println("Originator: Saving to Memento.");
return new Memento(state);
}
public void restoreFromMemento(Memento m) {
state = m.getSavedState();
System.out.println("Originator: State after restoring from Memento: "+state);
}
}
class Caretaker {
private ArrayList<Memento> savedStates = new ArrayList<Memento>();
public void addMemento(Memento m) { savedStates.add(m); }
public Memento getMemento(int index) { return savedStates.get(index); }
Behaioral patterns 184 of 205
}
class MementoExample {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Originator originator = new Originator();
originator.set("State1");
originator.set("State2");
caretaker.addMemento( originator.saveToMemento() );
originator.set("State3");
caretaker.addMemento( originator.saveToMemento() );
originator.set("State4");
originator.restoreFromMemento( caretaker.getMemento(1) );
}
}
Behaioral patterns 140 of 205
-ull 'b(ect Design Pattern
Intent
*he intent of a Null 7b8ect is to encapsulate the absence of an ob8ect by providing a substitutable
alternative that offers suitable default do nothing behavior. -n short! a design +here Jnothing +ill
come of nothingK
%se the Null 7b8ect pattern +hen
an ob8ect re=uires a collaborator. *he Null 7b8ect pattern does not introduce this
collaboration]it makes use of a collaboration that already e2ists
some collaborator instances should do nothing
you +ant to abstract the handling of null a+ay from the client
Proble*
Civen that an ob8ect reference may be optionally null! and that the result of a null check is to do
nothing or use some default value! ho+ can the absence of an ob8ect ] the presence of a null
reference ] be treated transparentlyO
Discussion
ometimes a class that re=uires a collaborator does not need the collaborator to do anything.
Do+ever! the class +ishes to treat a collaborator that does nothing the same +ay it treats one
that actually provides behavior.
(onsider for e2ample a simple screen saver +hich displays balls that move about the screen and
have special color effects. *his is easily achieved by creating a 6all class to represent the balls
and using a trategy pattern to control the ballAs motion and another trategy pattern to control
the ballAs color.
-t +ould then be trivial to +rite strategies for many different types of motion and color effects
and create balls +ith any combination of those. Do+ever! to start +ith you +ant to create the
simplest strategies possible to make sure everything is +orking. And these strategies could also
be useful later since you +ant as strategies as possible strategies.
Behaioral patterns 141 of 205
No+! the simplest strategy +ould be no strategy. *hat is do nothing! donAt move and donAt change
color. Do+ever! the trategy pattern re=uires the ball to have ob8ects +hich implement the
strategy interfaces. *his is +here the Null 7b8ect pattern becomes useful.
imply implement a NullMovementtrategy +hich doesnAt move the ball and a Null(olortrategy
+hich doesnAt change the ballAs color. 6oth of these can probably be implemented +ith essentially
no code. All the methods in these classes do JnothingK. *hey are perfect e2amples of the Null
7b8ect 'attern.
*he key to the Null 7b8ect pattern is an abstract class that defines the interface for all ob8ects of
this type. *he Null 7b8ect is implemented as a subclass of this abstract class. 6ecause it
conforms to the abstract classA interface! it can be used any place this type of ob8ect is needed. As
compared to using a special JnullK value +hich doesnAt actually implement the abstract interface
and +hich must constantly be checked for +ith special code in any ob8ect +hich uses the abstract
interface.
-t is sometimes thought that Null 7b8ects are over simple and JstupidK but in truth a Null 7b8ect
al+ays kno+s e2actly +hat needs to be done +ithout interacting +ith any other ob8ects. o in
truth it is very Jsmart.K
Structure
(lient >
re=uires a collaborator.
Abstract7b8ect >
declares the interface for (lientAs collaborator
implements default behavior for the interface common to all classes! as appropriate
^strong\5eal7b8ect^/strong\ >
defines a concrete subclass of Abstract7b8ect +hose instances provide useful behavior
that (lient e2pects
^strong\Null7b8ect^/strong\ >
provides an interface identical to Abstract7b8ectAs so that a null ob8ect can be
substituted for a real ob8ect
implements its interface to do nothing. ?hat e2actly it means to do nothing depends
on +hat sort of behavior (lient is e2pecting
+hen there is more than one +ay to do nothing! more than one Null7b8ect class may
be re=uired
Behaioral patterns 142 of 205
3ules of thu*b
*he Null 7b8ect class is often implemented as a ingleton. ince a null ob8ect usually does
not have any state! its state canAt change! so multiple instances are identical. 5ather than
use multiple identical instances! the system can 8ust use a single instance repeatedly.
-f some clients e2pect the null ob8ect to do nothing one +ay and some another! multiple
Null7b8ect classes +ill be re=uired. -f the do nothing behavior must be customi@ed at run
time! the Null7b8ect class +ill re=uire pluggable variables so that the client can specify
ho+ the null ob8ect should do nothing Esee the discussion of pluggable adaptors in the
Adapter patternG. *his may generally be a symptom of the Abstract7b8ect not having a
+ell defined EsemanticG interface.
A Null 7b8ect does not transform to become a 5eal 7b8ect. -f the ob8ect may decide to stop
providing do nothing behavior and start providing real behavior! it is not a null ob8ect. -t
may be a real ob8ect +ith a do nothing mode! such as a controller +hich can s+itch in and
out of read>only mode. -f it is a single ob8ect +hich must mutate from a do nothing ob8ect
to a real one! it should be implemented +ith the tate pattern or perhaps the 'ro2y
pattern. -n this case a Null tate may be used or the pro2y may hold a Null 7b8ect.
*he use of a null ob8ect can be similar to that of a 'ro2y! but the t+o patterns have
different purposes. A pro2y provides a level of indirection +hen accessing a real sub8ect!
thus controlling access to the sub8ect. A null collaborator does not hide a real ob8ect and
control access to it! it replaces the real ob8ect. A pro2y may eventually mutate to start
acting like a real sub8ect. A null ob8ect +ill not mutate to start providing real behavior! it
+ill al+ays provide do nothing behavior.
A Null 7b8ect can be a special case of the trategy pattern. trategy specifies several
(oncretetrategy classes as different approaches for accomplishing a task. -f one of those
approaches is to consistently do nothing! that (oncretetrategy is a Null7b8ect. /or
e2ample! a (ontroller is a ;ie+As trategy for handling input! and No(ontroller is the
trategy that ignores all input.
A Null 7b8ect can be a special case of the tate pattern. Normally! each (oncretetate has
some do nothing methods because theyAre not appropriate for that state. -n fact! a given
method is often implemented to do something useful in most states but to do nothing in at
least one state. -f a particular (oncretetate implements most of its methods to do
nothing or at least give null results! it becomes a do nothing state and as such is a null
state.
A Null 7b8ect can be used to allo+ a ;isitor to safely visit a hierarchy and handle the null
situation.
Null 7b8ect is a concrete collaborator class that acts as the collaborator for a client +hich
needs one. *he null behavior is not designed to be mi2ed into an ob8ect that needs some
do nothing behavior. -t is designed for a class +hich delegates to a collaborator all of the
behavior that may or may not be do nothing behavior.
'bserer Design Pattern
Intent
&efine a one>to>many dependency bet+een ob8ects so that +hen one ob8ect changes state!
all its dependents are notified and updated automatically.
1ncapsulate the core Eor common or engineG components in a ub8ect abstraction! and the
Behaioral patterns 14! of 205
variable Eor optional or user interfaceG components in an 7bserver hierarchy.
*he J;ie+K part of Model>;ie+>(ontroller.
Proble*
A large monolithic design does not scale +ell as ne+ graphing or monitoring re=uirements are
levied.
Discussion
&efine an ob8ect that is the JkeeperK of the data model and/or business logic Ethe ub8ectG.
&elegate all Jvie+K functionality to decoupled and distinct 7bserver ob8ects. 7bservers register
themselves +ith the ub8ect as they are created. ?henever the ub8ect changes! it broadcasts to
all registered 7bservers that it has changed! and each 7bserver =ueries the ub8ect for that
subset of the ub8ectAs state that it is responsible for monitoring.
*his allo+s the number and JtypeK of Jvie+K ob8ects to be configured dynamically! instead of
being statically specified at compile>time.
*he protocol described above specifies a JpullK interaction model. -nstead of the ub8ect
JpushingK +hat has changed to all 7bservers! each 7bserver is responsible for JpullingK its
particular J+indo+ of interestK from the ub8ect. *he JpushK model compromises reuse! +hile
the JpullK model is less efficient.
-ssues that are discussed! but left to the discretion of the designer! include: implementing event
compression Eonly sending a single change broadcast after a series of consecutive changes has
occurredG! having a single 7bserver monitoring multiple ub8ects! and ensuring that a ub8ect
notify its 7bservers +hen it is about to go a+ay.
*he 7bserver pattern captures the lionAs share of the Model>;ie+>(ontroller architecture that
has been a part of the malltalk community for years.
Structure
ub8ect represents
the core Eor
independent or
common or engineG
abstraction. 7bserver
represents the
variable Eor
dependent or optional
or user interfaceG
abstraction. *he
ub8ect prompts the
7bserver ob8ects to do their thing. 1ach 7bserver can call back to the ub8ect as needed.
5,a*ple
*he 7bserver defines a one>to>many relationship so that +hen one ob8ect changes state! the
others are notified and updated automatically. ome auctions demonstrate this pattern. 1ach
bidder possesses a numbered paddle that is used to indicate a bid. *he auctioneer starts the
bidding! and JobservesK +hen a paddle is raised to accept the bid. *he acceptance of the bid
Behaioral patterns 14) of 205
changes the bid price +hich is broadcast to all of the bidders in the form of a ne+ bid.
Chec0 list
$. &ifferentiate bet+een the core Eor independentG functionality and the optional Eor
dependentG functionality.
". Model the independent functionality +ith a Jsub8ectK abstraction.
). Model the dependent functionality +ith an JobserverK hierarchy.
9. *he ub8ect is coupled only to the 7bserver base class.
.. *he client configures the number and type of 7bservers.
0. 7bservers register themselves +ith the ub8ect.
3. *he ub8ect broadcasts events to all registered 7bservers.
4. *he ub8ect may JpushK information at the 7bservers! or! the 7bservers may JpullK the
information they need from the ub8ect.
3ules of thu*b
(hain of 5esponsibility! (ommand! Mediator! and 7bserver! address ho+ you can decouple
senders and receivers! but +ith different trade>offs. (hain of 5esponsibility passes a
sender re=uest along a chain of potential receivers. (ommand normally specifies a sender>
receiver connection +ith a subclass. Mediator has senders and receivers reference each
other indirectly. 7bserver defines a very decoupled interface that allo+s for multiple
receivers to be configured at run>time.
Mediator and 7bserver are competing patterns. *he difference bet+een them is that
7bserver distributes communication by introducing JobserverK and Jsub8ectK ob8ects!
+hereas a Mediator ob8ect encapsulates the communication bet+een other ob8ects. ?eAve
found it easier to make reusable 7bservers and ub8ects than to make reusable
Mediators.
7n the other hand! Mediator can leverage 7bserver for dynamically registering colleagues
and communicating +ith them.
Behaioral patterns 145 of 205
State Design Pattern
Intent
Allo+ an ob8ect to alter its behavior +hen its internal state changes. *he ob8ect +ill
appear to change its class.
An ob8ect>oriented state machine
+rapper F polymorphic +rappee F collaboration
Proble*
A monolithic ob8ectAs behavior is a function of its state! and it must change its behavior at run>
time depending on that state. 7r! an application is characteri2ed by large and numerous case
statements that vector flo+ of control based on the state of the application.
Discussion
*he tate pattern is a solution to the problem of ho+ to make behavior depend on state.
&efine a Jconte2tK class to present a single interface to the outside +orld.
&efine a tate abstract base class.
5epresent the different JstatesK of the state machine as derived classes of the tate base
class.
&efine state>specific behavior in the appropriate tate derived classes.
Maintain a pointer to the current JstateK in the Jconte2tK class.
*o change the state of the state machine! change the current JstateK pointer.
*he tate pattern does not specify +here the state transitions +ill be defined. *he choices are
t+o: the Jconte2tK ob8ect! or each individual tate derived class. *he advantage of the latter
option is ease of adding ne+ tate derived classes. *he disadvantage is each tate derived class
has kno+ledge of Ecoupling toG its siblings! +hich introduces dependencies bet+een subclasses.
A table>driven approach to designing finite state machines does a good 8ob of specifying state
transitions! but it is difficult to add actions to accompany the state transitions. *he pattern>based
approach uses code Einstead of data structuresG to specify state transitions! but it does a good 8ob
of accomodating state transition actions.
Structure
*he state machineAs interface is encapsulated in the J+rapperK class. *he +rappee hierarchyAs
interface mirrors the +rapperAs interface +ith the e2ception of one additional parameter. *he
e2tra parameter allo+s +rappee derived classes to call back to the +rapper class as necessary.
(omple2ity that +ould other+ise drag do+n the +rapper class is neatly compartmented and
encapsulated in a polymorphic hierarchy to +hich the +rapper ob8ect delegates.
Behaioral patterns 141 of 205
5,a*ple
*he tate pattern allo+s an ob8ect to change its behavior +hen its internal state changes. *his
pattern can be observed in a vending machine. ;ending machines have states based on the
inventory! amount of currency deposited! the ability to make change! the item selected! etc. ?hen
currency is deposited and a selection is made! a vending machine +ill either deliver a product
and no change! deliver a product and change! deliver no product due to insufficient currency on
deposit! or deliver no product due to inventory depletion.
Chec0 list
$. -dentify an e2isting class! or create a ne+ class! that +ill serve as the Jstate machineK
from the clientAs perspective. *hat class is the J+rapperK class.
". (reate a tate base class that replicates the methods of the state machine interface. 1ach
method takes one additional parameter: an instance of the +rapper class. *he tate base
class specifies any useful JdefaultK behavior.
). (reate a tate derived class for each domain state. *hese derived classes only override
the methods they need to override.
9. *he +rapper class maintains a JcurrentK tate ob8ect.
.. All client re=uests to the +rapper class are simply delegated to the current tate ob8ect!
and the +rapper ob8ectAs this pointer is passed.
0. *he tate methods change the JcurrentK state in the +rapper ob8ect as appropriate.
3ules of thu*b
tate ob8ects are often ingletons.
/ly+eight e2plains +hen and ho+ tate ob8ects can be shared.
-nterpreter can use tate to define parsing conte2ts.
Behaioral patterns 142 of 205
trategy has " different implementations! the first is similar to tate. *he difference is in
binding times Etrategy is a bind>once pattern! +hereas tate is more dynamicG.
*he structure of tate and 6ridge are identical Ee2cept that 6ridge admits hierarchies of
envelope classes! +hereas tate allo+s only oneG. *he t+o patterns use the same structure
to solve different problems: tate allo+s an ob8ectAs behavior to change along +ith its
state! +hile 6ridgeAs intent is to decouple an abstraction from its implementation so that
the t+o can vary independently.
*he implementation of the tate pattern builds on the trategy pattern. *he difference
bet+een tate and trategy is in the intent. ?ith trategy! the choice of algorithm is fairly
stable. ?ith tate! a change in the state of the Jconte2tK ob8ect causes it to select from its
JpaletteK of trategy ob8ects.
Strateg% Design Pattern
Intent
&efine a family of algorithms! encapsulate each one! and make them interchangeable. trategy
lets the algorithm vary independently from the clients that use it.
(apture the abstraction in an interface! bury implementation details in derived classes.
Proble*
7ne of the dominant strategies of ob8ect>oriented design is the Jopen>closed principleK.
/igure demonstrates ho+ this is routinely achieved > encapsulate interface details in a base class!
and bury implementation details in derived classes. (lients can then couple themselves to an
interface! and not have to e2perience the upheaval associated +ith change: no impact +hen the
number of derived classes changes! and no impact +hen the implementation of a derived class
changes.
A generic value of the soft+are community for years has been! Jma2imi@e cohesion and minimi@e
couplingK. *he ob8ect>oriented design approach sho+n in figure is all about minimi@ing coupling.
ince the client is coupled only to an abstraction Ei.e. a useful fictionG! and not a particular
reali@ation of that abstraction! the client could be said to be practicing Jabstract couplingK . an
ob8ect>oriented variant of the more generic e2hortation Jminimi@e couplingK.
A more popular characteri@ation of this Jabstract couplingK principle is J'rogram to an interface!
Behaioral patterns 148 of 205
not an implementationK.
(lients should prefer the Jadditional level of indirectionK that an interface Eor an abstract base
classG affords. *he interface captures the abstraction Ei.e. the Juseful fictionKG the client +ants to
e2ercise! and the implementations of that interface are effectively hidden.
Structure
*he -nterface entity could represent either an abstract base class! or the method signature
e2pectations by the client. -n the former case! the inheritance hierarchy represents dynamic
polymorphism. -n the latter case! the -nterface entity represents template code in the client and
the inheritance hierarchy represents static polymorphism.
5,a*ple
A trategy defines a set of algorithms that can be used interchangeably. Modes of transportation
to an airport is an e2ample of a trategy. everal options e2ist such as driving oneAs o+n car!
taking a ta2i! an airport shuttle! a city bus! or a limousine service. /or some airports! sub+ays
and helicopters are also available as a mode of transportation to the airport. Any of these modes
of transportation +ill get a traveler to the airport! and they can be used interchangeably. *he
traveler must chose the trategy based on tradeoffs bet+een cost! convenience! and time.
Chec0 list
$. -dentify an algorithm Ei.e. a behaviorG that the client +ould prefer to access through a
Jfle2 pointK.
". pecify the signature for that algorithm in an interface.
Behaioral patterns 144 of 205
). 6ury the alternative implementation details in derived classes.
9. (lients of the algorithm couple themselves to the interface.
3ules of thu*b
trategy is like *emplate Method e2cept in its granularity.
tate is like trategy e2cept in its intent.
trategy lets you change the guts of an ob8ect. &ecorator lets you change the skin.
tate! trategy! 6ridge Eand to some degree AdapterG have similar solution structures.
*hey all share elements of the Vhandle/bodyA idiom. *hey differ in intent > that is! they
solve different problems.
trategy has " different implementations! the first is similar to tate. *he difference is in
binding times Etrategy is a bind>once pattern! +hereas tate is more dynamicG.
trategy ob8ects often make good /ly+eights.
Te*plate &ethod Design Pattern
Intent
&efine the skeleton of an algorithm in an operation! deferring some steps to client subclasses.
*emplate Method lets subclasses redefine certain steps of an algorithm +ithout changing the
algorithmAs structure.
6ase class declares algorithm VplaceholdersA! and derived classes implement the placeholders.
Proble*
*+o different components have significant similarities! but demonstrate no reuse of common
interface or implementation. -f a change common to both components becomes necessary!
duplicate effort must be e2pended.
Discussion
*he component designer decides +hich steps of an algorithm are invariant Eor standardG! and
+hich are variant Eor customi@ableG. *he invariant steps are implemented in an abstract base
class! +hile the variant steps are either given a default implementation! or no implementation at
all. *he variant steps represent JhooksK! or JplaceholdersK! that can! or must! be supplied by the
componentAs client in a concrete derived class.
*he component designer mandates the re=uired steps of an algorithm! and the ordering of the
steps! but allo+s the component client to e2tend or replace some number of these steps.
*emplate Method is used prominently in frame+orks. 1ach frame+ork implements the invariant
pieces of a domainAs architecture! and defines JplaceholdersK for all necessary or interesting
client customi@ation options. -n so doing! the frame+ork becomes the Jcenter of the universeK!
and the client customi@ations are simply Jthe third rock from the sunK. *his inverted control
structure has been affectionately labelled Jthe Dolly+ood principleK > JdonAt call us! +eAll call
youK.
Structure
Behaioral patterns 200 of 205
*he implementation of template_methodEG is: call step_oneEG! call step_t+oEG! and call
step_threeEG. step_t+oEG is a JhookK method P a placeholder. -t is declared in the base class! and
then defined in derived classes. /rame+orks Elarge scale reuse infrastructuresG use *emplate
Method a lot. All reusable code is defined in the frame+orkAs base classes! and then clients of the
frame+ork are free to define customi@ations by creating derived classes as needed.
5,a*ple
*he *emplate Method defines a skeleton of an algorithm in an operation! and defers some steps
to subclasses. Dome builders use the *emplate Method +hen developing a ne+ subdivision. A
typical subdivision consists of a limited number of floor plans +ith different variations available
for each. ?ithin a floor plan! the foundation! framing! plumbing! and +iring +ill be identical for
each house. ;ariation is introduced in the later stages of construction to produce a +ider variety
of models.
Behaioral patterns 201 of 205
Chec0 list
$. 12amine the algorithm! and decide +hich steps are standard and +hich steps are peculiar
to each of the current classes.
". &efine a ne+ abstract base class to host the JdonAt call us! +eAll call youK frame+ork.
). Move the shell of the algorithm Eno+ called the Jtemplate methodKG and the definition of
all standard steps to the ne+ base class.
9. &efine a placeholder or JhookK method in the base class for each step that re=uires many
different implementations. *his method can host a default implementation P or P it can be
defined as abstract EMavaG or pure virtual E(FFG.
.. -nvoke the hook methodEsG from the template method.
0. 1ach of the e2isting classes declares an Jis>aK relationship to the ne+ abstract base class.
3. 5emove from the e2isting classes all the implementation details that have been moved to
the base class.
4. *he only details that +ill remain in the e2isting classes +ill be the implementation details
peculiar to each derived class.
3ules of thu*b
trategy is like *emplate Method e2cept in its granularity.
*emplate Method uses inheritance to vary part of an algorithm. trategy uses delegation
to vary the entire algorithm.
trategy modifies the logic of individual ob8ects. *emplate Method modifies the logic of an
entire class.
/actory Method is a speciali@ation of *emplate Method.
.isitor Design Pattern
Intent
5epresent an operation to be performed on the elements of an ob8ect structure. ;isitor
lets you define a ne+ operation +ithout changing the classes of the elements on +hich it
operates.
*he classic techni=ue for recovering lost type information.
&o the right thing based on the type of t+o ob8ects.
&ouble dispatch
Behaioral patterns 202 of 205
Proble*
Many distinct and unrelated operations need to be performed on node ob8ects in a heterogeneous
aggregate structure. Uou +ant to avoid JpollutingK the node classes +ith these operations. And!
you donAt +ant to have to =uery the type of each node and cast the pointer to the correct type
before performing the desired operation.
Discussion
;isitorAs primary purpose is to abstract functionality that can be applied to an aggregate
hierarchy of JelementK ob8ects. *he approach encourages designing light+eight 1lement classes >
because processing functionality is removed from their list of responsibilities. Ne+ functionality
can easily be added to the original inheritance hierarchy by creating a ne+ ;isitor subclass.
;isitor implements Jdouble dispatchK. 77 messages routinely manifest Jsingle dispatchK > the
operation that is e2ecuted depends on: the name of the re=uest! and the type of the receiver. -n
Jdouble dispatchK! the operation e2ecuted depends on: the name of the re=uest! and the type of
*?7 receivers Ethe type of the ;isitor and the type of the element it visitsG.
*he implementation proceeds as follo+s. (reate a ;isitor class hierarchy that defines a pure
virtual visitEG method in the abstract base class for each concrete derived class in the aggregate
node hierarchy. 1ach visitEG method accepts a single argument > a pointer or reference to an
original 1lement derived class.
1ach operation to be supported is modelled +ith a concrete derived class of the ;isitor hierarchy.
*he visitEG methods declared in the ;isitor base class are no+ defined in each derived subclass by
allocating the Jtype =uery and castK code in the original implementation to the appropriate
overloaded visitEG method.
Add a single pure virtual acceptEG method to the base class of the 1lement hierarchy. acceptEG is
defined to receive a single argument > a pointer or reference to the abstract base class of the
;isitor hierarchy.
1ach concrete derived class of the 1lement hierarchy implements the acceptEG method by simply
calling the visitEG method on the concrete derived instance of the ;isitor hierarchy that it +as
passed! passing its JthisK pointer as the sole argument.
1verything for JelementsK and JvisitorsK is no+ set>up. ?hen the client needs an operation to be
performed! EsGhe creates an instance of the ;istor ob8ect! calls the acceptEG method on each
1lement ob8ect! and passes the ;isitor ob8ect.
*he acceptEG method causes flo+ of control to find the correct 1lement subclass. *hen +hen the
visitEG method is invoked! flo+ of control is vectored to the correct ;isitor subclass. acceptEG
dispatch plus visitEG dispatch e=uals double dispatch.
*he ;isitor pattern makes adding ne+ operations Eor utilitiesG easy > simply add a ne+ ;isitor
derived class. 6ut! if the subclasses in the aggregate node hierarchy are not stable! keeping the
;isitor subclasses in sync re=uires a prohibitive amount of effort.
An ackno+ledged ob8ection to the ;isitor pattern is that is represents a regression to functional
decomposition > separate the algorithms from the data structures. ?hile this is a legitimate
interpretation! perhaps a better perspective/rationale is the goal of promoting non>traditional
behavior to full ob8ect status.
Structure
*he 1lement hierarchy is instrumented +ith a Juniversal method adapterK. *he implementation
of acceptEG in each 1lement derived class is al+ays the same. 6ut P it cannot be moved to the
1lement base class and inherited by all derived classes because a reference to this in the
1lement class al+ays maps to the base type 1lement.
Behaioral patterns 20! of 205
?hen the polymorphic first&ispatchEG method is called on an abstract /irst ob8ect! the concrete
type of that ob8ect is JrecoveredK. ?hen the polymorphic second&ispatchEG method is called on
an abstract econd ob8ect! its concrete type is JrecoveredK. *he application functionality
appropriate for this pair of types can no+ be e2ercised.
5,a*ple
*he ;isitor pattern represents an operation to be performed on the elements of an ob8ect
structure +ithout changing the classes on +hich it operates. *his pattern can be observed in the
Behaioral patterns 20) of 205
operation of a ta2i company. ?hen a person calls a ta2i company Eaccepting a visitorG! the
company dispatches a cab to the customer. %pon entering the ta2i the customer! or ;isitor! is no
longer in control of his or her o+n transportation! the ta2i EdriverG is.
Chec0 list
$. (onfirm that the current hierarchy Ekno+n as the 1lement hierarchyG +ill be fairly stable
and that the public interface of these classes is sufficient for the access the ;isitor classes
+ill re=uire. -f these conditions are not met! then the ;isitor pattern is not a good match.
". (reate a ;isitor base class +ith a visitE1lementN22G method for each 1lement derived
type.
). Add an acceptE;isitorG method to the 1lement hierarchy. *he implementation in each
1lement derived class is al+ays the same P acceptE ;isitor v G Y v.visitE this GI Z. 6ecause of
cyclic dependencies! the declaration of the 1lement and ;isitor classes +ill need to be
interleaved.
9. *he 1lement hierarchy is coupled only to the ;isitor base class! but the ;isitor hierarchy is
coupled to each 1lement derived class. -f the stability of the 1lement hierarchy is lo+! and
the stability of the ;isitor hierarchy is highI consider s+apping the VrolesA of the t+o
hierarchies.
.. (reate a ;isitor derived class for each JoperationK to be performed on 1lement ob8ects.
visitEG implementations +ill rely on the 1lementAs public interface.
0. *he client creates ;isitor ob8ects and passes each to 1lement ob8ects by calling acceptEG.
3ules of thu*b
*he abstract synta2 tree of -nterpreter is a (omposite Etherefore -terator and ;isitor are
also applicableG.
-terator can traverse a (omposite. ;isitor can apply an operation over a (omposite.
*he ;isitor pattern is like a more po+erful (ommand pattern because the visitor may
Behaioral patterns 205 of 205
initiate +hatever is appropriate for the kind of ob8ect it encounters.
*he ;isitor pattern is the classic techni=ue for recovering lost type information +ithout
resorting to dynamic casts.
-otes
*he November "### issue of Mava'ro has an article by Mames (ooper Eauthor of a Mava companion
to the Co/G on the ;isitor design pattern. De suggests it Jturns the tables on our ob8ect>oriented
model and creates an e2ternal class to act on data in other classes Q +hile this may seem
unclean Q there are good reasons for doing it.K
Dis primary e2ample. uppose you have a hierarchy of 1mployee>1ngineer>6oss. *hey all en8oy a
normal vacation day accrual policy! but! 6osses also participate in a JbonusK vacation day
program. As a result! the interface of class 6oss is different than that of class 1ngineer. ?e
cannot polymorphically traverse a (omposite>like organi@ation and compute a total of the
organi@ationAs remaining vacation days. J*he ;isitor becomes more useful +hen there are several
classes +ith different interfaces and +e +ant to encapsulate ho+ +e get data from these
classes.K
Dis benefits for ;isitor include:
Add functions to class libraries for +hich you either do not have the source or cannot
change the source
7btain data from a disparate collection of unrelated classes and use it to present the
results of a global calculation to the user program
Cather related operations into a single class rather than force you to change or derive
classes to add these operations
(ollaborate +ith the (omposite pattern
;isitor is not good for the situation +here JvisitedK classes are not stable. 1very time a ne+
(omposite hierarchy derived class is added! every ;isitor derived class must be amended.

Potrebbero piacerti anche