Prototype Pattern

Classic GOF Constructional Design Patterns

 
  

Intent

Similar to the Object Pool pattern, the Prototype Pattern seeks to reduce the time and cost of creating objects. In the case of the Prototype Pattern, a base-line object (the prototype) is copied or cloned and returned rather than creating the object from scratch.

This pattern is very common when:

  • you desire performance in creating / returning a costly to create object
  • you want to initialize an object to a custom known state repeatedly
  • the use of the new operator is considered harmful
prototype patterns
  

Problem

When building applications, you often come across objects that are either expensive to create or regularly need to be pre-configured to a specific state that you want to have occur automatically. In some scenarios, the cost of creating new objects is high enough to impact application performance. Alternately, the time spent configuring an object could be high or make the code cluttered. This is where the prototype design pattern shines.

  

Discussion

The Prototype Pattern is a high performance method of returning objects with a known state to a caller. Unlike the Object Pool which creates collections of objects to pass out, the Prototype maintains one instance of the desired object and doles our "copies" as required.

The Prototype pattern should be considered when:

  • Composition, creation and representation of objects should be decoupled from the system
  • Classes to be created are specified at run-time
  • You need to hide the complexity of creating new instance from the client
  • Creating an object is an expensive operation and it would be more efficient to copy an object.
  • Objects are required that are similar to existing objects.

Consider the following typical problem case. You have an object and want to create a duplicate. How would you typically do it? First, you need to create a fresh object of the same class. Then you have to go over through all fields of the original object and copy their values to the new object. But there is (often) a catch. Not all objects can be copied this way. Some of the objects can have private fields not accessible from the outside - short of some languages abilities to do things like reflection.

The final problem with this "create and copy" approach is that you also tightly couple actual classes - losing the ability to use objects strictly through their defined interfaces.

The prototype pattern helps in this scenario by taking an already created and configured instance of an object (the prototype) and handing out copies as needed. Unlike the object pool, the prototype pattern does not limit or typically control the number of copies that have been created (although this functionality could be added if desired).

  

Structure

Fundamentally, a Prototype pattern is implemented by having the desired objects support a cloneable interface.


prototype structure

The basic prototype design pattern consists of a basic interface that all prototype instances need to implement. In the diagram above, this interface is identified as the Prototype Interface. The Prototype Interface declares the common interface for all objects that allow cloning. It allows cloning objects without tight coupling to their concrete classes. Usually, the prototype interface contains a single clone method.

The implementation of clone method is similar for all classes. The method creates an object of a current class and copies all its field values into the new object. Most of the programming languages allow accessing private fields in an object of the same class, so the copying process is straightforward.

Objects that can be cloned are called prototypes. Sometimes, especially when your objects have a ton of fields and hundreds of possible configurations, prototypes can serve as an alternative to sub-classing. In this case, the program creates a bunch of prototypes beforehand and then clones them instead of reconstructing objects from scratch.

The actual implementation of the "copy" or "clone" functionality depends greatly on the platform or language that you use to implement it. Some of the classic OO languages have native support for cloning (shallow and deep) where as other languages leave it up to the designer to implement this behavior.

  

Practical Example

As stated in the STRUCTURE discussion above, the Prototype is a common approach to returning or configuring expensive or time consuming objects in an application. Our example is going to be pretty basic to cover the typical scenarios in where you will find this pattern useful. Here, we will create and deliver some (simulated) expensive to create resources.


prototype example structure

In our examples, we will be using the prototype pattern to create employees of various types.

  

Code Samples

Below, you will find examples of the Prototype Pattern implemented in four different commonly used languages. Each one of the examples implements the exact same scenario as described in the PRACTICAL EXAMPLE section above.

Each sample will use the prototype pattern to create and return an expensive object.


C# Prototype Code Sample

In this C# example, we take advantage of a number of features of the .NET platform that make this extremely simple to implement. The version provided here is highly performant a it relies on the "shallow copy" functionality.


Java Prototype Code Sample

In this Java example, we are taking a simplistic approach to solve the employee sample.


Typescript Prototype Code Sample

In this TypeScript example, it is again about as basic as it can get.


JavaScript Prototype Code Sample

In this JavaScript example, the Prototype is implemented very simply using only a single prototype, but it could easily be extended to include multiple possible prototype instances.


  

Considerations

  1. Validate that you have a need to use a prototype:
    • You must create objects that are expensive to create, or
    • You must create objects that are complex to configure before use.
  2. Add a clone() method to all objects to be delivered
  3. Where interfaces are supported, make all objects to be delivered support the prototype interface
  4. Create a "cache" or storage system for the prototypes that you will copy
  5. Optionally, create a factory method that will select the correct prototype and return a copy
  

Additional Notes

  • Prototypes perform creation through delegation.
  • Prototype doesn't require subclassing, but it does require an "initialize" operation. Factory Method requires sub-classing, but doesn't require Initialize.
  • Designs that make heavy use of the Composite and Decorator patterns often can benefit from Prototype as well.
  • Prototype co-opts one instance of a class for use as a breeder of all future instances.
  • Prototype is unique among the other creational patterns in that it doesn't require a class – only an object. Object-oriented languages like Self and Omega that do away with classes completely rely on prototypes for creating new objects.
  • Complex objects with lots of references to other objects can be difficult to clone.