Prototype Pattern in Java

1. Introduction

In this tutorial, we’re going to learn about one of the Creational Design Patterns – the Prototype pattern. At first, we’ll explain this pattern and then proceed to implement it in Java.

We’ll also discuss some of its advantages and disadvantages.

2. Prototype Pattern

The Prototype pattern is generally used when we don’t want to keep creating new instances of a class. This is quite helpful in places where the cost of creating an object is high. In such cases, we want to minimize the use of resources such as memory.

Let’s use an analogy to better understand this pattern.

In some games, we want trees or buildings in the background. We may realize that we don’t have to create new trees or buildings and render them on the screen every time the character moves.

So, we create an instance of the tree first. Then we can create as many trees as we want from this instance (prototype) and update their positions. We may also choose to change the color of the trees for a new level in the game.

The Prototype pattern is quite similar. Instead of creating new objects, we just have to clone the prototypical instance.

3. UML Diagram

Prototype Pattern

In the diagram, we see that the client is telling the prototype to clone itself and create an object. Prototype is an interface and declares a method for cloning itself. ConcretePrototype1 and ConcretePrototype2 implement the operation to clone themselves.

4. Implementation

One of the ways we can implement this pattern in Java is by using the clone() method. To do this, we’d implement the Cloneable interface.

When we’re trying to clone, we should decide between making a shallow or a deep copy. Eventually, it boils down to the requirements.

For example, if the class contains only primitive and immutable fields, we may use a shallow copy.

If it contains references to mutable fields, we should go for a deep copy. We might do that with copy constructors or serialization and deserialization.

Let’s take the example we mentioned earlier and imagine that creating new instances of Tree is expensive.

Now, let’s proceed to see how to apply the Prototype pattern by using the Cloneable interface:

public class Tree implements Cloneable {

    // ...
    @Override
    public Tree clone() {
        Tree tree = null;
        try {
            tree = (Tree) super.clone();
        } catch (CloneNotSupportedException e) {
            // ...
        }
        return tree;
    }

    // ...
}

5. Testing

Now let’s test it:

public class TreePrototypesUnitTest {

    @Test
    public void givenATreePrototypeWhenClonedThenCreateA_Clone() {
        // ...

        Tree tree = new Tree(mass, height);
        tree.setPosition(position);
        Tree anotherTree = tree.clone();
        anotherTree.setPosition(otherPosition);

        assertEquals(position, tree.getPosition());
        assertEquals(otherPosition, anotherTree.getPosition());
    }
}

We see that the tree has been cloned from the prototype and we have two different instances of Tree. We’ve just updated the position in the clone and retained the other values.

6. Advantages & Disadvantages

This pattern is appropriate when object creation is expensive. Also, it’s handy when our new object is only slightly different from our existing one. Doing so can also help improve the performance of the application.

Prototype pattern, just like every other design pattern, should be used only when it’s appropriate. Since we are cloning the objects, the process could get complex when there are many classes, thereby resulting in a mess. Additionally, it’s difficult to clone classes that have circular references.

7. Conclusion

In this tutorial, we learned the key concepts of the Prototype pattern and saw how to implement it in Java. We also discussed some of its pros and cons.

As usual, the source code for this article is available over on Github.