Prototype

Why Prototype:
Need to duplicate objects with different dynamic types

Prototype is particularly useful with static languages like C++, where classes are not objects, and little or no type information is available at run-time.
Benefits:
1.       Adding and removing products at run-time.
2.       Specifying new objects by varying values
3.       Specifying new objects by varying structure.
4.       Reduced subclassing.
5.       Configuring an application with classes dynamically.
Difficulty:
The implementation of clone operation: especially when their internals include objects that don't support copying or have circular references.

Implementation
Solutions:
-          Provide a polymorphic method that returns an instance of the same type as the object on which the method is called
-          Polymorphic method calls copy constructor, returns base class pointer or reference to concrete derived type
-           
Issues have to be considered
1.       Using a prototype manager.
When the number of prototypes in a system isn't fixed (that is, they can be created and destroyed dynamically), keep a registry of available prototypesA prototype manager is an associative store that returns the prototype matching a given key. It has operations for registering a prototype under a key and for unregistering it. Clients can change or even browse through the registry at run-time.
2.       Implementing the Clone operation.
The default copy constructor in C++ does a member-wise copy, which means pointers will be shared between the copy and the original. Cloning prototypes with complex structures usually requires a deep copy, because the clone and the original must be independent.

3.       Initializing clones.

Sample Code
a MazePrototypeFactory subclass of the MazeFactory class.
class MazePrototypeFactory : public MazeFactory {
public:
MazePrototypeFactory(Maze*, Wall*, Room*, Door*);
virtual Maze* MakeMaze() const;
virtual Room* MakeRoom(int) const;
virtual Wall* MakeWall() const;
virtual Door* MakeDoor(Room*, Room*) const;
private:
Maze* _prototypeMaze;
Room* _prototypeRoom;
Wall* _prototypeWall;
Door* _prototypeDoor;
};

MazePrototypeFactory::MazePrototypeFactory ( Maze* m, Wall* w, Room* r, Door* d ) {
_prototypeMaze = m;
_prototypeWall = w;
_prototypeRoom = r;
_prototypeDoor = d;
}

Wall* MazePrototypeFactory::MakeWall () const {
return _prototypeWall->Clone();
}
Door* MazePrototypeFactory::MakeDoor (Room* r1, Room *r2) const {
Door* door = _prototypeDoor->Clone();
door->Initialize(r1, r2);
return door;
}

MazeGame game;

MazePrototypeFactory simpleMazeFactory(
new Maze, new Wall, new Room, new Door
);
Maze* maze = game.CreateMaze(simpleMazeFactory);

To change the type of maze, we initialize MazePrototypeFactory with a different set of prototypes. The following call creates a maze with a BombedDoor and a RoomWithABomb:

MazePrototypeFactory bombedMazeFactory(
new Maze, new BombedWall, new RoomWithABomb, new Door
);

Note:  An object that can be used as a prototype, such as an instance of Wall, must support the Clone operation. It must also have a copy constructor for cloning. It may also need a separate operation for reinitializing internal state.

Revised for prototype
class Door : public MapSite {
public:
Door();
Door(const Door&);   // a copy constructor for cloning
virtual void Initialize(Room*, Room*);  // a separate operation for reinitializing internal state
virtual Door* Clone() const; // support the Clone operation
virtual void Enter();
Room* OtherSideFrom(Room*);
private:
Room* _room1;
Room* _room2;
};

// a copy constructor for cloning
Door::Door (const Door& other) {
_room1 = other._room1;
_room2 = other._room2;
}
// a separate operation for reinitializing internal state
void Door::Initialize (Room* r1, Room* r2) {
_room1 = r1;
_room2 = r2;
}
// support the Clone operation
Door* Door::Clone () const {
return new Door(*this);

}

Comments

Popular posts from this blog

Sudoku

Longest prefix matching - trie

Climbing Stairs