Thursday, February 4, 2010

Prototype pattern

Prototype

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying that prototype.

  • A prototype pattern is used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used for example when the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) is prohibitively expensive for a given application.
  • Implementation: Declare an abstract base class that specifies a pure virtual clone() method. Any class that needs a "polymorphic constructor" capability derives itself from the abstract base class, and implements the clone() operation.
  • Here the client code first invokes the factory method. This factory method, depending on the parameter, finds out concrete class. On this concrete class call to the Clone() method is called and the object is returned by the factory method.
  • This is sample code which is a sample implementation of Prototype method. We have the detailed description of all the components here.
    • "Record" class which is a pure virtual class which is having pure virtual method "Clone()".
    • "CarRecord", "BikeRecord" and "PersonRecord" as concrete implementation of "Record" class.
    • An enum RECORD_TYPE_en as one to one mapping of each concrete implementation of "Record" class.
    • "RecordFactory" class which is having Factory method "CreateRecord(...)". This method requires an enum RECORD_TYPE_en as parameter and depending on this parameter it returns the concrete implementation of "Record" class.
  /**

* Implementation of Prototype Method
**/

#include
#include

using namespace std;

enum RECORD_TYPE_en
{
CAR,
BIKE,
PERSON
};

/**
* Record is the Prototype
*/


class Record
{
public :

Record() {}

~Record() {}

Record* Clone()=0;

virtual void Print()=0;
};

/**
* CarRecord is Concrete Prototype
*/


class CarRecord : public Record
{
private :
string m_oStrCarName;

u_int32_t m_ui32ID;

public :

CarRecord(string _oStrCarName,u_int32_t _ui32ID)
: Record(), m_oStrCarName(_oStrCarName),
m_ui32ID(_ui32ID)
{
}

CarRecord(CarRecord& _oCarRecord)
: Record()
{
m_oStrCarName = _oCarRecord.m_oStrCarName;
m_ui32ID = _oCarRecord.m_ui32ID;
}

~CarRecord() {}

Record* Clone()
{
return new CarRecord(*this);
}

void Print()
{
cout << "Car Record" << endl
<< "Name : " << m_oStrCarName << endl
<< "Number: " << m_ui32ID << endl << endl;
}
};


/**
* BikeRecord is the Concrete Prototype
*/


class BikeRecord : public Record
{
private :
string m_oStrBikeName;

u_int32_t m_ui32ID;

public :
BikeRecord(string _oStrBikeName,u_int32_t _ui32ID)
: Record(), m_oStrBikeName(_oStrBikeName),
m_ui32ID(_ui32ID)
{
}

BikeRecord(BikeRecord& _oBikeRecord)
: Record()
{
m_oStrBikeName = _oBikeRecord.m_oStrBikeName;
m_ui32ID = _oBikeRecord.m_ui32ID;
}

~BikeRecord() {}

Record* Clone()
{
return new BikeRecord(*this);
}

void Print()
{
cout << "Bike Record" << endl
<< "Name : " << m_oStrBikeName << endl
<< "Number: " << m_ui32ID << endl << endl;
}
};


/**
* PersonRecord is the Concrete Prototype
*/


class PersonRecord : public Record
{
private :
string m_oStrPersonName;

u_int32_t m_ui32Age;

public :
PersonRecord(string _oStrPersonName, u_int32_t _ui32Age)
: Record(), m_oStrPersonName(_oStrPersonName),
m_ui32Age(_ui32Age)
{
}

PersonRecord(PersonRecord& _oPersonRecord)
: Record()
{
m_oStrPersonName = _oPersonRecord.m_oStrPersonName;
m_ui32Age = _oPersonRecord.m_ui32Age;
}

~PersonRecord() {}

Record* Clone()
{
return new PersonRecord(*this);
}

void Print()
{
cout << "Person Record" << endl
<< "Name : " << m_oStrPersonName << endl
<< "Age : " << m_ui32Age << endl << endl ;
}
};


/**
* RecordFactory is the client
*/


class RecordFactory
{
private :
map<RECORD_TYPE_en, Record* > m_oMapRecordReference;

public :
RecordFactory()
{
m_oMapRecordReference[CAR] = new CarRecord("Ferrari", 5050);
m_oMapRecordReference[BIKE] = new BikeRecord("Yamaha", 2525);
m_oMapRecordReference[PERSON] = new PersonRecord("Tom", 25);
}

~RecordFactory()
{
delete m_oMapRecordReference[CAR];
delete m_oMapRecordReference[BIKE];
delete m_oMapRecordReference[PERSON];
}

Record* CreateRecord(RECORD_TYPE_en enType)
{
return m_oMapRecordReference[enType]->Clone();
}
};

int main()
{
RecordFactory* poRecordFactory = new RecordFactory();

Record* poRecord;
poRecord = poRecordFactory->CreateRecord(CAR);
poRecord->Print();
delete poRecord;

poRecord = poRecordFactory->CreateRecord(BIKE);
poRecord->Print();
delete poRecord;

poRecord = poRecordFactory->CreateRecord(PERSON);
poRecord->Print();
delete poRecord;

delete poRecordFactory;
return 0;
}

Another example:

To implement the pattern, declare an abstract base class that specifies a pure virtual clone() member function. Any class that needs a "polymorphic constructor" capability derives itself from the abstract base class, and implements the clone() operation.

The client, instead of writing code that invokes the "new" operator on a hard-wired class name, calls the clone() member function on the prototype, calls a factory member function with a parameter designating the particular concrete derived class desired, or invokes the clone() member function through some mechanism provided by another design pattern.

 class CPrototypeMonster

{
protected:
CString _name;
public:
CPrototypeMonster();
CPrototypeMonster( const CPrototypeMonster& copy );
~CPrototypeMonster();

virtual CPrototypeMonster* Clone() const=0; // This forces every derived class to provide an overload for this function.
void Name( CString name );
CString Name() const;
};

class CGreenMonster : public CPrototypeMonster
{
protected:
int _numberOfArms;
double _slimeAvailable;
public:
CGreenMonster();
CGreenMonster( const CGreenMonster& copy );
~CGreenMonster();

virtual CPrototypeMonster* Clone() const;
void NumberOfArms( int numberOfArms );
void SlimeAvailable( double slimeAvailable );

int NumberOfArms() const;
double SlimeAvailable() const;
};

class CPurpleMonster : public CPrototypeMonster
{
protected:
int _intensityOfBadBreath;
double _lengthOfWhiplikeAntenna;
public:
CPurpleMonster();
CPurpleMonster( const CPurpleMonster& copy );
~CPurpleMonster();

virtual CPrototypeMonster* Clone() const;

void IntensityOfBadBreath( int intensityOfBadBreath );
void LengthOfWhiplikeAntenna( double lengthOfWhiplikeAntenna );

int IntensityOfBadBreath() const;
double LengthOfWhiplikeAntenna() const;
};

class CBellyMonster : public CPrototypeMonster
{
protected:
double _roomAvailableInBelly;
public:
CBellyMonster();
CBellyMonster( const CBellyMonster& copy );
~CBellyMonster();

virtual CPrototypeMonster* Clone() const;

void RoomAvailableInBelly( double roomAvailableInBelly );
double RoomAvailableInBelly() const;
};

CPrototypeMonster* CGreenMonster::Clone() const
{
return new CGreenMonster(*this);
}

CPrototypeMonster* CPurpleMonster::Clone() const
{
return new CPurpleMonster(*this);
}

CPrototypeMonster* CBellyMonster::Clone() const
{
return new CBellyMonster(*this);
}

A client of one of the concrete monster classes only needs a reference (pointer) to a CPrototypeMonster class object to be able to call the ‘Clone’ function and create copies of that object. The function below demonstrates this concept:

 void DoSomeStuffWithAMonster( const CPrototypeMonster* originalMonster )

{
CPrototypeMonster* newMonster = originalMonster->Clone();
ASSERT( newMonster );

newMonster->Name("MyOwnMoster");
// Add code doing all sorts of cool stuff with the monster.
delete newMonster;
}

Now originalMonster can be passed as a pointer to CGreenMonster, CPurpleMonster or CBellyMonster.

No comments:

Post a Comment