100%(1)Il 100% ha trovato utile questo documento (1 voto)
217 visualizzazioni205 pagine
This document provides an introduction and overview of design patterns. It discusses the uses of design patterns, including providing tested solutions to common software problems and improving communication between developers. It then summarizes the main categories of design patterns - creational patterns, which cover object creation, structural patterns, which cover class and object composition, and behavioral patterns, which cover object communication. Each category lists some of the common patterns that fall within that category.
This document provides an introduction and overview of design patterns. It discusses the uses of design patterns, including providing tested solutions to common software problems and improving communication between developers. It then summarizes the main categories of design patterns - creational patterns, which cover object creation, structural patterns, which cover class and object composition, and behavioral patterns, which cover object communication. Each category lists some of the common patterns that fall within that category.
This document provides an introduction and overview of design patterns. It discusses the uses of design patterns, including providing tested solutions to common software problems and improving communication between developers. It then summarizes the main categories of design patterns - creational patterns, which cover object creation, structural patterns, which cover class and object composition, and behavioral patterns, which cover object communication. Each category lists some of the common patterns that fall within that category.
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% ðod (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% ðod (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% ðod 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% ðod 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% ðod 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% ðod 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 << "), width = " << w << ", height = " << h << endl; } virtual void draw() { cout << "RectangleAdapter: draw." << 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 ðod &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 ðod 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.