Menu Close

Object Oriented Design Pattern: Prototype

prototype

Explanation

The Prototype design pattern is a creational patter which at the core clones an object in a specific state. Basically, you set the attributes (variables) of a class and create a new instance with the exact same values of those attributes. The object creation process goes via a method which usually supports (and should) the deep cloning of objects.

Use cases/possible benefits:

  • You need more objects of which are in a specific state. E.g.: Imagine a computer game where you upgrade a unit. Each new unit you build should have the upgrade, thus you can clone the latest update of the unit, which is the new prototype.
  • It might reduce the need to write more (sub)classes.
  • It might reduce the (computational) cost to create a new object.

Pitfalls

  • The implementation of (deep) cloning can be complex.
  • The runtime complexity might be higher compared to less compile time class definitions.
  • The clone method returns an abstraction of the cloned object which might omit the enforcement of compile-time type checking.
  • The cost of object creation might not self-evidently be less costly. For instance there might be edge cases where deep cloning is not necessary.
  • If the prototype state changes, so will the next instances of the clones of that object.

Java example

For this Java example I used serialization from a dependency to clone objects. Maven dependency:

<dependency>
  <groupId>org.netbeans.external</groupId>
  <artifactId>org-apache-commons-lang3</artifactId>
  <version>RELEASE130</version>
</dependency>
package com.chosengambit.designpatterns;

import java.io.Serializable;
import org.apache.commons.lang3.SerializationUtils;

public interface IClone extends Serializable { 
    
    default Serializable getSerializedClone() {
        return SerializationUtils.clone(this);
    }
}
Java

package com.chosengambit.designpatterns;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Prototype implements IClone {
    
    private int id;
    private String test = "test";
    protected List<String> codes = Arrays.asList("37432", "74265", "76742");
    public boolean b = false;
    
    public Prototype() { }
    
    public Prototype(int id, String test, List<String> codes, boolean b) {
        this.id = id;
        this.test = test;
        this.codes = codes;
        this.b = b;
    } 
    
    public void setList(List<String> codes) {
        this.codes = codes;
    }
    
    public void printFields() {
        try {
            Field[] fieldArray = this.getClass().getDeclaredFields();
    
            for (int i = 0; i < fieldArray.length; i++) {
                Field f = fieldArray[i];    
                f.setAccessible(true);
                System.out.println("Copying variable: "+
                        f.getName()+" with value "+
                        f.get(this)+" and type "+
                        f.getType().getSimpleName());                
            }
        }
        catch(Exception e) {
            // beautiful error handling here
        }        
    }
}
Java

package com.chosengambit.designpatterns;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
       Prototype original = new Prototype(1, "instance", Arrays.asList("a","b","c"), true);
       Prototype clone = (Prototype) original.getSerializedClone();
       
       // print object fields, they should contain the same data
       original.printFields();
       clone.printFields();
       
       // altered data of cloned object
       clone.setList(Arrays.asList("123", "456", "789"));
       clone.b = false;
       
       // print object fields
       original.printFields();
       clone.printFields();       
    }
}
Java
Output:

Copying variable: id with value 1 and type int
Copying variable: test with value instance and type String
Copying variable: codes with value [a, b, c] and type List
Copying variable: b with value true and type boolean

Copying variable: id with value 1 and type int
Copying variable: test with value instance and type String
Copying variable: codes with value [a, b, c] and type List
Copying variable: b with value true and type boolean

Copying variable: id with value 1 and type int
Copying variable: test with value instance and type String
Copying variable: codes with value [a, b, c] and type List
Copying variable: b with value true and type boolean

# clone with changes
Copying variable: id with value 1 and type int
Copying variable: test with value instance and type String
Copying variable: codes with value [123, 456, 789] and type List
Copying variable: b with value false and type boolean

Python example

import copy


class Prototype:
    id: int
    name: str
    properties: []

    def clone(self):
        return copy.deepcopy(self)
Python

# main.py

from Prototype import Prototype

try:
    p = Prototype()
    p.id = 1
    p.name = "House"
    p.properties = ["Stone", "Red", "Flat roof"]

    print(vars(p))

    clone = p.clone()

    print(vars(clone))

    p.name = "Castle"
    clone.id = 2
    clone.properties.append("Large")

    print(vars(p))
    print(vars(clone))

except Exception as e:
    print(e)

Python
Output:

{'id': 1, 'name': 'House', 'properties': ['Stone', 'Red', 'Flat roof']}
{'id': 1, 'name': 'House', 'properties': ['Stone', 'Red', 'Flat roof']}
{'id': 1, 'name': 'Castle', 'properties': ['Stone', 'Red', 'Flat roof']}
# clone with changes
{'id': 2, 'name': 'House', 'properties': ['Stone', 'Red', 'Flat roof, 'Large']}

Conclusion

The Prototype design pattern might come in handy in several use cases. As with all design patterns, overusing it can impact your code in a bad way. The examples use a more general way of implementation. It is of course also possible to implement the cloning functionality in other ways.

An alternative to this pattern is the Factory Method design pattern.

References

Freeman, E., Bates, B., & Sierra, K. (2004). Head first design patterns.

Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software.

Wikipedia contributors. (2024, 10 september). Software design pattern. Wikipedia. https://en.wikipedia.org/wiki/Software_design_pattern

Related Posts