Fundamentals 12 min read

Understanding the Prototype Design Pattern in Java

The article explains the Prototype design pattern in Java, covering its definition, class diagram, implementation with Cloneable, shallow vs deep copying, advantages, use cases, Spring prototype scope, and provides complete code examples illustrating cloning of Sheep, Goat, and Lamb objects.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding the Prototype Design Pattern in Java

Problem

If you have an object and want to create an exact copy, you need to instantiate a new object of the same class and copy all member variables.

This straightforward approach can be inefficient for complex objects, may not handle private fields, and requires re‑initialisation each time.

Basic Introduction

Prototype pattern specifies creating objects by copying a prototype instance.

It is a creational design pattern that lets you clone existing objects without depending on their concrete classes.

The core mechanism is calling clone() on a prototype object.

Class Diagram

The diagram includes the following participants:

Prototype : an interface that declares the cloning method.

ConcretePrototype : classes that implement clone() and may handle special cloning logic.

Client : obtains a prototype instance and clones it to create new objects.

Example

We use a sheep‑herding story to demonstrate the pattern.

1. Prototype class (implements Cloneable )

@Setter
 @Getter
 @NoArgsConstructor
 @AllArgsConstructor
 class Sheep implements Cloneable {
     private String name;
     private Integer age;
     private String color;
 
     @Override
     protected Sheep clone() {
         Sheep sheep = null;
         try {
             sheep = (Sheep) super.clone();
         } catch (Exception e) {
             System.out.println(e.getMessage());
         }
         return sheep;
     }
 }

2. Concrete prototypes

public class Goat extends Sheep {
    public void graze() {
        System.out.println("山羊去吃草");
    }
}
public class Lamb extends Sheep {
    public void graze() {
        System.out.println("羔羊去吃草");
    }
}

3. Client

public class Client {
    static List
sheepList = new ArrayList<>();
    public static void main(String[] args) {
        Goat goat = new Goat();
        goat.setName("山羊");
        goat.setAge(3);
        goat.setColor("灰色");
        for (int i = 0; i < 5; i++) {
            sheepList.add(goat.clone());
        }

        Lamb lamb = new Lamb();
        lamb.setName("羔羊");
        lamb.setAge(2);
        lamb.setColor("白色");
        for (int i = 0; i < 5; i++) {
            sheepList.add(lamb.clone());
            System.out.println(lamb.hashCode()+","+lamb.clone().hashCode());
        }

        for (Sheep sheep : sheepList) {
            System.out.println(sheep.toString());
        }
    }
}

The prototype pattern delegates cloning to the actual object, decoupling client code from concrete classes.

Advantages

Cloning via Object.clone() is a native method and often faster than repeatedly calling new , especially for large objects.

It simplifies object creation, making it as easy as copy‑paste in a document.

Useful when many similar objects need to be created inside loops, improving overall performance.

Applicable Scenarios

When object creation is expensive or complex.

When you need to copy objects without tying code to their concrete classes.

When subclass differences are only in initialization, allowing reduction of subclass count.

Prototype Pattern in Spring

Spring beans are singleton by default, but you can define a bean with scope="prototype" to obtain a new instance on each request.

<bean id="sheep" class="priv.starfish.prototype.Sheep" scope="prototype">
   <property name="name" value="肖恩"/>
   <property name="age" value="2"/>
   <property name="color" value="白色"/>
</bean>

Fetching the bean multiple times yields distinct objects.

Precautions

Cloning bypasses constructors; therefore, any initialization logic in constructors is not executed, which can conflict with patterns like Singleton.

Java's default clone() performs a shallow copy—reference‑type fields are shared.

Shallow vs Deep Copy

Shallow copy duplicates primitive fields but copies references for objects, leading to shared sub‑objects. Deep copy creates independent copies of referenced objects as well.

Shallow Copy Example

Sheep s = new Sheep();
 s.setName("sss");
 s.friend = new Sheep();
 s.friend.setName("喜洋洋");
 Sheep s1 = s.clone();
 System.out.println(s == s1); // false
 System.out.println(s.friend == s1.friend); // true

Deep Copy Approaches

Override clone() to recursively clone referenced objects.

Use object serialization to produce a deep copy.

When an object contains only primitive fields, the default clone behaves like a deep copy; otherwise, you must implement deep cloning manually.

design patternsJavaCloningdeep copyshallow copyPrototype Pattern
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.