# Prototype Design Pattern explained in 2 minutes

### Problem Statement

Functional programming heavily prefers Immutability i.e. objects should not be mutated. But what about the cases when we need to modify a specific field of an object? You need to create a copy of the entire object and update that specific field.

Okay, but how do I copy an existing object? Prototype design pattern to the rescue!

```java
public class Car implements Cloneable {
    private final String name;

    private final List<Integer> mileage;

    public Car(String name, List<Integer> mileage) {
        this.name = name;
        this.mileage = mileage;
    }

    // Clone using Copy constructor
    public Car(Car existing) {
        this.name = existing.name;
        // deep copy
        this.mileage = List.copyOf(existing.getMileage());
    }

    // Clone using the default clone method.
    @Override
    public Car clone() {
        try {
            // by default provides shallow cloning i.e. only clones the references
            return (Car) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    public String getName() {
        return name;
    }

    public List<Integer> getMileage() {
        return mileage;
    }
}
```

In the above code, we demonstrated two ways to create a clone of an Object in Java - using a custom copy constructor or by implementing the `Cloneable` interface.

`Cloneable` is a very special interface in Java - it's a *marker* interface - it does not have any method. When an Object implements Cloneable, JVM changes the `protected()` nature of the `clone()` method in `Object` class to `public`() - without which it throws a `CloneNotSupportedException`. By default, it provides a *shallow* clone i.e. only copies the reference.  
Using Cloneable to create clones is highly discouraged because of its complicated nature.

Copy Constructors on the other hand are very intuitive and allow you to exactly control the behaviour. You can tweak the code to easily use shallow or deep copying as and when required.

```java
public class Main {
    public static void main(String[] args) {
        testPrototype();
    }

    public static void testPrototype() {
        List<Integer> mileage = new ArrayList<>();
        mileage.add(10);
        mileage.add(20);
        Car originalCar = new Car("bentley", mileage);
        Car shallowClone = originalCar.clone();
        Car deepClone = new Car(originalCar);

        List<Integer> clonedMileage = shallowClone.getMileage();
        System.out.println(shallowClone.getName() + " " + clonedMileage);
        mileage.set(0, 50);
        // updating the mileage also updated the clonedMileage because they both 
        // point to the same object (shallow copy)
        System.out.println(clonedMileage.get(0).equals(50));

        // updating the mileage didn't affect the deep cloned object
        System.out.println(deepClone.getMileage().get(0).equals(10));
    }
}
// Output
bentley [10, 20]
true
true
```

### Bonus Section

If you are using `Lombok` in your application to create boilerplate Java code, then you can use `@With` or `@Builder(toBuilder = true)` to create clones.

`@With` allows you to create a cloned object by updating only a specific field whereas `toBuilder()` allows you to override as many fields as possible. You can chain multiple `with()` to update multiple fields in succession but that would create a lot of garbage.

### What's the benefit?

* Domain logic to clone the object does not spill out to the outer application.
    

### What's the drawback?

* Circular dependency can become tricky to resolve. You would need to exclude a specific field to resolve the conflict.
    
* Need to be aware of the type of cloning being performed - shallow/deep.
    

### References

* [https://www.baeldung.com/lombok-builder](https://www.baeldung.com/lombok-builder)
    
* [https://projectlombok.org/features/With](https://projectlombok.org/features/With)
