Author image

Prototype Design Pattern


Difficulty:
1/5


Implementing Prototype Design Pattern like a boss and then laughing it off.
Bonus: lewd way of spawning arrays of objects from a prototypical instance (check spawnMonsterArray).

The prototype pattern is a creational software design pattern, that is used when the type of object(s) to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to:

  • avoid subclasses of an object creator, like the factory pattern does
  • avoid the inherent cost of creating a new object in the standard way (like using new) when it can be prohibitively expensive for a given application

Design

  • define an abstract Prototype class with a clone() method that returns a copy of itself
  • create subclasses of Prototype . These will be the concrete types. Implement the clone method (and whichever other one you want of course)
  • create a Spawner/Factory class with a private Prototype pointer (sort of like the Queen bee who never leaves the hive) and a spawnObject() method. The Spawner class resembles a Prototype factory function. The spawnObject() method simply calls clone on its prototype object and returns it.
  • in the Spawner class call the prototype's clone method to return a copy of the prototype object based on the concrete subobject.

Notice there is a 1-to-1 relationship between a prototype and a factory/spawner. So create as many prototypical objects and their respective factory/spawner objects as the concrete subclasses you want to create.

Usage

  1. create the prototype(s): std::unique_ptr<Monster> skeletonPrototype = std::make_unique<Skeleton>();
  2. create the factory/spawner: std::unique_ptr<MonsterSpawner> skeletonFactory = std::make_unique<MonsterSpawner>( skeletonPrototype.get() );
  3. spawn a copy of the prototype object using the spawner: std::unique_ptr<Monster> skeleton = skeletonFactory->spawnMonster();
  4. or spawn multiple copies: auto skeletons = spawnMonsterArray<Skeleton>( skeletonFactory.get(), 10 );

The tricky aspect of this pattern in C++ is memory management & ownership of the objects. Thankfully, with C++11 onwards we have smart pointers and they can alleviate a large part of that burden. Still you have to make careful considerations concerning ownership. Create the prototypes as unique_ptrs, create the arrays/vectors as owners (containers should always be owners). On the other hand, the factories don't need to own anything, they simply make use of the passed pointer to do their thing. Give the code a careful read.

Prototype objects can be added and removed at run-time. One neat aspect about this pattern is that it doesn't just clone the class of the prototype, it clones its state too. This means we could make a spawner for fast ghosts, weak ghosts, or slow ghosts just by creating an appropriate prototype Ghost object.

I used Windows 8.1 x86_64, Visual Studio 2017 to build the project.

Github

Github repository link. Snag the code now!


0 likes