Prototype
An introduction to the Prototype Creational Pattern
By John Haggerty
Review: Abstract Factory
- An AbstractFactory class is used by the Client to create Products
- The type of ConcreteFactory class being used changes the type of Products created, but this is transparent to the Client
- Disadvantage: A different ConcreteFactory class is needed for every type of product
Abstract Factory Structure
The Solution: Prototyping
- Instead of creating a ConcreteFactory class for each type of Product and using the applicable one, simply make a prototypical instance of the Product that you want to be created
- The various Products must have Clone() methods which create and return duplicates of themselves
- When a new Product is needed, the Client simply calls the Clone() method of its prototype and uses the returned Product
An Example: Warcraft III
- Buildings create Units
- For example, a Barracks can create Footmen, Riflemen, or Knights
An Example: Warcraft III
- Units are all essentially the same with varying statistics, and can be represented by a Unit class
class Unit {
public:
Unit();
...
protected:
ThreeDeeModel model;
float size;
float attackDamage;
...
};
- Buildings, similarly, can be represented by a Building class which creates Units
class Building {
public:
Building();
...
protected:
ThreeDeeModel model;
};
- Our first instinct may be to create a subclass for each type of building
class Barracks : public Building {
public:
Unit TrainFootman();
Unit TrainRifleman();
Unit TrainKnight();
...
};
class TownHall : public Building {
public:
Unit TrainPeasant();
...
};
...
An Example: Warcraft III
- However, we can avoid subclassing the Building class by making use of prototypes
class Building {
public:
Building();
Unit TrainUnit(int whichUnit) {
return unitPrototypes[whichUnit].Clone();
}
...
protected:
ThreeDeeModel model;
Unit unitPrototypes[4];
int numUnits;
};
- Note that the Unit class must contain a Clone method which returns a duplicate of itself
class Unit {
public:
Unit();
Unit Clone();
...
protected:
ThreeDeeModel model;
float size;
float attackDamage;
...
};
An Example: Warcraft III
- Any building can now create as many units of a type as necessary, simply by cloning the original
- The prototypes of units must be loaded at run-time before the game begins, but we avoided making a large number of nearly identical subclasses
- Since Buildings are all now essentially the same, it is easy to create new types of buildings or modify old ones. The Warcraft III World Editor allows this functionality for custom maps
Advantages of Prototyping
- Products can be added and removed at run-time
- The number of necessary (sub)classes are reduced
- Different types of Products don't have to be hardcoded
- Users can define their own prototypes, save, and reuse them
Disadvantages of Prototyping
- All Product classes must have a Clone() method
- The Product classes may already exist, and it may be difficult to modify them
- Cloning can be difficult when Products contain objects which don't support copying
- Cloning can be difficult when Products contain circular references