# The Prototype Pattern with Java Examples

### What Is the Prototype Pattern?

A **prototype** is a **pre-existing object that you use as a template** to create new objects. Instead of creating an object from scratch, with `new`You **clone an existing one** that already has the desired state.

The **Prototype Pattern** is a creational design pattern that lets you:

* Create new objects by **copying** (not instantiating) a prototype
    
* Avoid repeating complex setup logic
    
* Keep code flexible by not tying it to specific class constructors
    

For example, here’s how you would copy an object without this pattern:

```java
Book book1 = new Book("Effective Java", "Joshua Bloch", List.of("Item 1", "Item 2"));

Book book2 = new Book(
    book1.getTitle(),
    book1.getAuthor(),
    new ArrayList<>(book1.getChapters())
);
```

You have to manually copy each field — error-prone and repetitive.

---

### 🧬 With Prototype Pattern (via copy method)

```java
Book book1 = new Book("Effective Java", "Joshua Bloch", List.of("Item 1", "Item 2"));
Book book2 = book1.copy();
```

Much cleaner and encapsulated — the `copy()` method inside `Book` handles the duplication safely.

**In Java, you have two alternatives to implement the pattern: implementing the Cloneable interface or defining a custom** `copy()` **method.**

---

### Ways to Implement the Prototype Pattern in Java

#### Option 1: Using `Cloneable` + `super.clone()`

🧩 Before We Start: What Is `Cloneable` and What Does It Do?

To use `super.clone()` in Java, your class must implement the `Cloneable` interface:

```
public interface Cloneable { }
```

It’s a **marker interface** — it has no methods. Its purpose is to signal the JVM that your object supports cloning. If your class does **not** implement `Cloneable`, calling `super.clone()` will throw a `CloneNotSupportedException`.

**What You Must Do:**

1. Implement `Cloneable`
    
2. Override `clone()` and make it `public`
    
3. Handle `CloneNotSupportedException` or throw it
    
4. Return the correct type by downcasting
    

Here’s the implementation of the Prototype pattern following this recipe:

```java
public class Document implements Cloneable {
    private String title;
    private List<String> paragraphs;

    public Document(String title, List<String> paragraphs) {
        this.title = title;
        this.paragraphs = paragraphs;
    }

    @Override
    public Document clone() {
        try {
            return (Document) super.clone(); // Shallow copy
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // This should never happen
        }
    }
}
```

✅ **Pros**: fast, native shallow copy, you can skip the manual work of copying each field

❌ **Cons**: This is shallow copying, which might violate the principle of least surprise (more on that later)

#### Option 2: Custom Copy (No `Cloneable`)

You implement your copy method manually and have full control of what you copy and follow the copying approach (deep or shallow) that best follows your needs:

```java
public class Document {
    private String title;
    private List<String> paragraphs;

    public Document(String title, List<String> paragraphs) {
        this.title = title;
        this.paragraphs = paragraphs;
    }

    public Document copy() {
        return new Document(title, new ArrayList<>(paragraphs));
    }
}
```

✅ **Pros**: clearer, performs deep copy, no weird `CloneNotSupportedException`

❌ **Cons**: more manual work

---

### 📃 Shallow vs Deep Copy: Key Differences

Whether you're using `Cloneable` or a manual copy method, you can implement a deep or shallow copy of your objects. Understanding shallow vs deep copy is necessary:

#### Shallow Copy Example

```java
Document original = new Document("My Title", new ArrayList<>(List.of("Intro", "Content")));
Document copy = original.clone();

copy.getParagraphs().set(0, "Modified");
System.out.println(original.getParagraphs()); // Prints: ["Modified", "Content"]
```

This happens because both `Document` instances share the same `paragraphs` list.

#### Deep Copy Example (with Cloneable)

```java
@Override
public Document clone() {
    try {
        Document copy = (Document) super.clone();
        copy.paragraphs = new ArrayList<>(this.paragraphs); // Deep copy the list
        return copy;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}
```

Now, modifying `copy.paragraphs` won't affect the original object.

This deep copy can also be achieved without `Cloneable` by writing a custom `copy()` method. The key is duplicating mutable fields to avoid shared references.

---

### ⚖️ Performance vs. Clarity: Should You Use `super.clone()`?

> **"The Principle of Least Surprise"** says that code should behave in a way that minimizes confusion for those reading or using it. Users should not be surprised by how something works.

`Cloneable` in Java violates this principle because:

* It defines no methods, yet calling `super.clone()` depends on it.
    
* Forgetting to implement it leads to unexpected `CloneNotSupportedException`.
    
* Even when it works, it does a shallow copy by default, which can lead to shared internal state.
    

In short:

* `super.clone()` is **fast** but potentially confusing.
    

* Manual `copy()` methods are **clearer** and allow full control.
    

Use what fits your case:

* Go with `clone()` for speed and simplicity **if** you're confident about the structure.
    
* Prefer manual copies for **clarity**, **immutability**, and **safe separation of state**.
    

---

### 🔻 Disadvantages of the Prototype Pattern

1. **Complex Cloning Logic:** Deep copying can be error-prone and requires careful handling of nested objects, references, and circular dependencies.
    
2. **Cloning Limitations in Java**
    
    * Using `clone()` (especially in Java) may confuse developers unfamiliar with how shallow vs deep copies work.
        
    * Java’s `Cloneable` interface is considered flawed:
        
        * It lacks a `clone()` method in the interface.
            
        * `Object.clone()` is protected, requiring workarounds.
            
        * Doesn't support deep cloning out of the box.
            
3. **Hard to Maintain**
    
    * If objects evolve (e.g., new fields), developers must update the cloning logic, increasing maintenance effort and risk of bugs.
        

### Conclusion

The Prototype Pattern lets you **create new objects by copying** existing ones. It can improve performance, simplify object creation, and reduce coupling to concrete classes.

You can implement it using Java's `Cloneable` interface and `super.clone()` or define your own copy methods:

* Use `super.clone()` when speed matters and your object is simple
    
* Use manual copying when clarity, immutability, or safety is more important
    

Choose the approach that best matches the complexity and goals of your project.
