// Purpose. Prototype #include // creation via delegation // Discussion. The architect has done class Stooge { public: // an admirable job of decoupling the virtual Stooge* clone() = 0; // client from Stooge concrete derived virtual void slapStick() = 0; // classes and exercising polymor- }; // phism. But there remains coup- // ling where instances are actually class Factory { // created. If we design an "extra public: // level of indirection" (a "factory") static Stooge* create( int i ); // and have clients use it (instead of private: // "new"), then the last bit of coup- static Stooge* prototypes_[4]; // ling goes away. The Prototype }; // pattern suggests delegating the // creation service to contained ob- void main( void ) // jects that know how to "clone" { // themselves. This strategy also Stooge* roles[10]; // allows us to retire the "case" int in, j, i = 0; // statement in main(). cout << "L(1) M(2) C(3) Go(0): "; #include cin >> in; while (in) { class Stooge { public: roles[i++] = Factory::create(in); virtual void slapStick() = 0; cout << "L(1) M(2) C(3) Go(0): "; }; cin >> in; } class Larry : public Stooge { public: for (j=0; j < i; j++) void slapStick() { roles[j]->slapStick(); cout << "Larry: poke eyes" << endl; } for (j=0; j < i; j++) }; delete roles[j]; class Moe : public Stooge { public: } void slapStick() { cout << "Moe: slap head" class Larry : public Stooge { public: << endl; } Stooge* clone() { return new Larry; } }; void slapStick() { class Curly : public Stooge { public: cout << "Larry: poke eyes" void slapStick() { << endl; } cout << "Curly: suffer abuse" }; << endl; } class Moe : public Stooge { public: }; Stooge* clone() { return new Moe; } void slapStick() { void main( void ) cout << "Moe: slap head" { << endl; } Stooge* roles[10]; }; int in, j, i = 0; class Curly : public Stooge { public: Stooge* clone() {return new Curly; } cout << "L(1) M(2) C(3) Go(0): "; void slapStick() { cin >> in; cout << "Curly: suffer abuse" while (in) { << endl; } if (in == 1) }; roles[i++] = new Larry; else if (in == 2) Stooge* Factory::prototypes_[] = { 0, roles[i++] = new Moe; new Larry, new Moe, new Curly }; else Stooge* Factory::create( int i ) { roles[i++] = new Curly; return prototypes_[i]->clone(); } cout << "L(1) M(2) C(3) Go(0): "; cin >> in; } // L(1) M(2) C(3) Go(0): 1 // L(1) M(2) C(3) Go(0): 2 for (j=0; j < i; j++) // L(1) M(2) C(3) Go(0): 3 roles[j]->slapStick(); // L(1) M(2) C(3) Go(0): 1 // L(1) M(2) C(3) Go(0): 0 for (j=0; j < i; j++) // Larry: poke eyes delete roles[j]; // Moe: slap head } // Curly: suffer abuse // Larry: poke eyes //////////////////// Same example, single column \\\\\\\\\\\\\\\\\\\\ // Purpose. Prototype // creation via delegation // Discussion. The architect has done // an admirable job of decoupling the // client from Stooge concrete derived // classes and exercising polymor- // phism. But there remains coup- // ling where instances are actually // created. If we design an "extra // level of indirection" (a "factory") // and have clients use it (instead of // "new"), then the last bit of coup- // ling goes away. The Prototype // pattern suggests delegating the // creation service to contained ob- // jects that know how to "clone" // themselves. This strategy also // allows us to retire the "case" // statement in main(). #include using namespace std; class Stooge { public: virtual void slapStick() = 0; }; class Larry : public Stooge { public: void slapStick() { cout << "Larry: poke eyes" << endl; } }; class Moe : public Stooge { public: void slapStick() { cout << "Moe: slap head" << endl; } }; class Curly : public Stooge { public: void slapStick() { cout << "Curly: suffer abuse" << endl; } }; int main( void ) { Stooge* roles[10]; int in, j, i = 0; cout << "L(1) M(2) C(3) Go(0): "; cin >> in; while (in) { if (in == 1) roles[i++] = new Larry; else if (in == 2) roles[i++] = new Moe; else roles[i++] = new Curly; cout << "L(1) M(2) C(3) Go(0): "; cin >> in; } for (j=0; j < i; j++) roles[j]->slapStick(); for (j=0; j < i; j++) delete roles[j]; system( "pause" ); } // L(1) M(2) C(3) Go(0): 1 // L(1) M(2) C(3) Go(0): 2 // L(1) M(2) C(3) Go(0): 3 // L(1) M(2) C(3) Go(0): 1 // L(1) M(2) C(3) Go(0): 0 // Larry: poke eyes // Moe: slap head // Curly: suffer abuse // Larry: poke eyes #include using namespace std; class Stooge { public: virtual Stooge* clone() = 0; virtual void slapStick() = 0; }; class Factory { public: static Stooge* create( int i ); private: static Stooge* prototypes_[4]; }; int main( void ) { Stooge* roles[10]; int in, j, i = 0; cout << "vlh L(1) M(2) C(3) Go(0): "; cin >> in; while (in) { roles[i++] = Factory::create(in); cout << "L(1) M(2) C(3) Go(0): "; cin >> in; } for (j=0; j < i; j++) roles[j]->slapStick(); for (j=0; j < i; j++) delete roles[j]; system( "pause" ); } class Larry : public Stooge { public: Stooge* clone() { return new Larry; } void slapStick() { cout << "Larry: poke eyes" << endl; } }; class Moe : public Stooge { public: Stooge* clone() { return new Moe; } void slapStick() { cout << "Moe: slap head" << endl; } }; class Curly : public Stooge { public: Stooge* clone() {return new Curly;} void slapStick() { cout << "Curly: suffer abuse" << endl; } }; Stooge* Factory::prototypes_[] = { 0, new Larry, new Moe, new Curly }; Stooge* Factory::create( int i ) { return prototypes_[i]->clone(); } // Purpose. Prototype design pattern demo // // Discussion. Image base class provides the mechanism for storing, // finding, and cloning the prototype for all derived classes. Each // derived class specifies a private static data member whose // initialization "registers" a prototype of itself with the base class. // When the client asks for a "clone" of a certain type, the base class // finds the prototype and calls clone() on the correct derived class. #include 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() { 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() { 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 }; void 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]; } // LandSatImage::draw 1 // LandSatImage::draw 2 // LandSatImage::draw 3 // SpotImage::draw 1 // LandSatImage::draw 4 // SpotImage::draw 2 // SpotImage::draw 3 // LandSatImage::draw 5