//
Purpose. Prototype #include <iostream.h>
// 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 <iostream.h> 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
// 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
<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() { 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