Patterns

What is a Prototype Pattern?

The Prototype Pattern is a programming pattern used in software engineering and is part of the group of creational patterns. It may be used in any object-oriented programming language, such as Java, Python, C++, and so on. What it does is to instantiate new objects based on a template structure. Instead of instantiating new objects and invoking their constructor, existing objects known as the prototype are copied.

What is the motivation to use the copy / clone mechanism of the Prototype Pattern, rather than just instantiating them without this pattern? Well, one reason might very much be the performance, as creating new objects can have a tendency to be more expensive than just copying existing ones. This though depends on the chosen type of cloning that the programmer implements within the clone method. Another reason might well be that the Prototype Pattern helps reducing code complexity by abstracting the process of object creation, meaning that the client code can make new instances without knowing what exact class will be instantiated. Hence, the code becomes more readable.

So what is the Prototype Pattern used for? This pattern is used in various software systems and frameworks. Examples of real-world use include the Database Access, Configuration Management, and Testing and Mocking.

Database Access
Data can be loaded from the database into prototype objects to avoid redundant database queries. By preloading data, the application performance can be significantly enhanced, especially in scenarios with high read-to-write ratios.

Configuration Management
Configuration can be stored as objects. If so, the Prototype Pattern can be used to manage the configuration by cloning predefined prototypes with different settings or parameters and then adapting them to their needs.

Testing and Mocking
In unit testing and mocking frameworks, the Prototype Pattern can be used to create mock objects by cloning prototypes of real objects. This allows for isolated testing of components without affecting the original objects.

What is the structure of a Prototype Pattern?

  1. Prototype
    Interface or abstract class that defines the methods for cloning an object. Usually there is a clone() method included.
  2. ConcretePrototype1 and ConcretePrototype2
    These classes are cloned by clients to create new objects. Hence, clients do not create objects by instantiating them directly. Instead they clone existing prototypes.

Example Codes

There are a number of programming languages where the Prototype Pattern can prove useful. Every language that supports the construct of classes can make use of this pattern.

Java Example

The following example is a Java application putting the Prototype Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. Being the smallest possible code example, this little project consists of four Java files:

  1. Prototype.java
  2. ConcretePrototype1.java
  3. ConcretePrototype2.java
  4. Main.java

The first thing that needs to be defined is the Prototype. The Prototype serves as the contract that concrete prototype classes must adhere to in order to participate in the Prototype Pattern. There should at least be a method like clone() that the concrete prototype classes implement to enable to create a copy of themselves.

public interface Prototype {
    Prototype clone();
}

The next thing is to create concrete prototype classes that implement the Prototype interface. This also pushes them to implement the clone() method to guarantee that they can be cloned.

public class ConcretePrototype1 implements Prototype {
    private String value;

    public ConcretePrototype1(String value) {
        this.value = value;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype1(this.value);
    }

    @Override
    public String toString() {
        return "value = '" + this.value + "'";
    }
}
public class ConcretePrototype2 implements Prototype {
    private String value;

    public ConcretePrototype2(String value) {
        this.value = value;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype2(this.value);
    }

    @Override
    public String toString() {
        return "value = '" + this.value + "'";
    }
}

And that is it already. The main construct of the Prototype Pattern consists of these four Java files. The only thing that remains is to apply their logic within the executing main class. The main(...) method creates an instance each of ConcretePrototype1 and ConcretePrototype2 and puts them into variables of the type Prototype. Then both instances are cloned and put into two more variables of the type Prototype. The last four lines of code print text to the command line interface in order to compare all four variables, showing that they are all different objects.

public class Main {
    public static void main(String[] args) {
        System.out.println("Prototype Pattern in Java");
        System.out.println("-------------------------");
        System.out.println();

        // Create concrete prototypes.
        Prototype cp1 = new ConcretePrototype1("cp1");
        Prototype cp2 = new ConcretePrototype2("cp2");

        // Clone concrete prototypes.
        Prototype cp3 = cp1.clone();
        Prototype cp4 = cp2.clone();

        // Compare concrete prototypes.
        System.out.println("cp1: " + cp1.toString() + ", hash = " + cp1.hashCode());
        System.out.println("cp2: " + cp2.toString() + ", hash = " + cp2.hashCode());
        System.out.println("cp3: " + cp3.toString() + ", hash = " + cp3.hashCode());
        System.out.println("cp4: " + cp4.toString() + ", hash = " + cp4.hashCode());
    }
}

There also needs to be a Manifest.txt file within the same folder. This is a metadata file used primarily in JAR files. It contains information about the JAR file itself and its contents. It is placed within thie META-INF folder within the JAR archive file structure.

Main-Class: Main

To compile this code into an executable Java application which would be a JAR file, a couple of commands need to be executed from within the same directory. The commands are found within the build file.

build.cmd (Windows)
@echo off

javac *.java
jar cvfm PrototypeDemo.jar Manifest.txt *.class
build (MacOS / Linux)
#!/bin/bash

javac *.java
jar cvfm PrototypeDemo.jar Manifest.txt *.class

Now that the compilation has taken place, there are new files within the same directory. Every JAVA file has its equivalent CLASS file, and there is also a file called PrototypeDemo.jar. This is the Java application that needs to be executed. The command for that is within the run file.

run.cmd (Windows)
@echo off

java -jar PrototypeDemo.jar
run (MacOS / Linux)
#!/bin/bash

java -jar PrototypeDemo.jar

Testing the Java Example

Now that all the files are ready and within their correct location they can be put to test. First we need to compile the Java code and then we can execute it to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.

build.cmd (Windows)

build.cmd (Windows)

build (MacOS / Linux)

build (MacOS / Linux)

run.cmd (Windows)

run.cmd (Windows)

run (MacOS / Linux)

run (MacOS / Linux)

Python Example

The following example is a Python application putting the Prototype Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. As this is the smallest possible example, this little project consists of four Python files:

  1. prototype.py
  2. concrete_prototype_1.py
  3. concrete_prototype_2.py
  4. main.py

The first thing that needs to be defined is the Prototype. The Prototype serves as the contract that concrete prototype classes must adhere to in order to participate in the Prototype Pattern. There should at least be a method like clone() that the concrete prototype classes implement to enable to create a copy of themselves.

from abc import ABC, abstractmethod

class Prototype(ABC):
    @abstractmethod
    def clone(self):
        pass
from prototype import Prototype

class ConcretePrototype1(Prototype):
    def __init__(self, value):
        self._value = value

    def clone(self):
        return ConcretePrototype1(self._value)
    
    def __str__(self):
        return "value = '" + self._value + "'"
from prototype import Prototype

class ConcretePrototype2(Prototype):
    def __init__(self, value):
        self._value = value

    def clone(self):
        return ConcretePrototype2(self._value)
    
    def __str__(self):
        return "value = '" + self._value + "'"

And that is it already. The main construct of the Prototype Pattern consists of these four Python files. The only thing that remains is to apply their logic within the executing main class. The main() method creates an instance each of ConcretePrototype1 and ConcretePrototype2 and puts them into variables. Then both instances are cloned and put into two more variables. The last four lines of code print text to the command line interface in order to compare all four variables, showing that they are all different objects.

from concrete_prototype_1 import ConcretePrototype1
from concrete_prototype_2 import ConcretePrototype2

def main():
    print("Prototype Pattern in Python")
    print("---------------------------")
    print()

    # Create concrete prototypes.
    cp1 = ConcretePrototype1("cp1")
    cp2 = ConcretePrototype2("cp2")

    # Clone concrete prototypes.
    cp3 = cp1.clone()
    cp4 = cp2.clone()

    # Compare concrete prototypes.
    print("cp1:", cp1, ", hash =", hash(cp1))
    print("cp2:", cp2, ", hash =", hash(cp2))
    print("cp3:", cp3, ", hash =", hash(cp3))
    print("cp4:", cp4, ", hash =", hash(cp4))
    
if __name__ == "__main__":
    main()

There is no need to compile anything in Python. The code is executed directly using the python command under Windows and the python3 command under MacOS / Linux.

run.cmd (Windows)
@echo off

python main.py
run (MacOS / Linux)
#!/bin/bash

python3 main.py

Testing the Python Example

Now that all the files are ready and within their correct location they can be put to test. Python does not need to be compiled before being run. Therefore we can execute it right away to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.

run.cmd (Windows)

run.cmd (Windows)

run (MacOS / Linux)

run (MacOS / Linux)

More Information

So, where do I have my information from? In general, there are lots of places on the internet that offer great information. But that is just one source of information. Another source would be books. Those have the advantage that usually several people work on the same book before it is released, raising the chance for distribution of good and proven information.

Head First - Design Patterns

Building Extensible and Maintainable Object-Oriented Software

A book that has proven to be a valuable asset within my personal library is Head First - Design Patterns by the publisher O'Reilly. It has a fun approach to this topic, having recurring characters, such as the Guru, the Developer, the Skeptical Developer, Joe, and many more.

Java Design Patterns

A Hands-On Experience with Real-World Examples

Another highly valuable book is Java Design Patterns: A Hands-On Experience with Real-World Examples by the publisher Apress. It offers a conservative and rather scientific approach to the subject. It also offers code examples in Java, although any object-oriented programming language applies to the design patterns shown here.

We use cookies

We deeply value your privacy and want to ensure you have the best possible experience on our website. By accepting our Cookie Consent, you're helping us tailor your visit to your preferences, providing you with personalized content and ensuring that all features work seamlessly.

However, if you choose not to accept our Cookie Consent, some parts of the website may not function optimally. We want you to enjoy full access to all the great content and features we offer, so we encourage you to consider accepting our Cookie Consent.

Please be aware that even if you choose not to accept our Cookie Consent, you can still browse our website. However, some functionalities may be limited, and you may not experience the website to its fullest potential.

For more details on how we handle your data, please refer to our Privacy Policy.