Skip to main content

Prototype Pattern

Prototype is a creational design pattern that lets you copy existing objects without making your code dependent on their classes.

Problem

We want to make an exact copy of an object (copy every property). The most intuitive method is to make a new object with constructor or setter methods.

However, if an object has private fields, it's not possible to clone it with the above methods.

Solution

Use an interface containing a single method, clone.

You can even copy private fields because most programming languages let objects access private fields of other objects that belong to the same class.

Sample Code

code

import java.util.Objects;

public abstract class Shape {
public int x;
public int y;
public String color;

public Shape() {
}

public Shape(Shape target) {
if (target != null) {
this.x = target.x;
this.y = target.y;
this.color = target.color;
}
}

public abstract Shape clone();

@Override
public boolean equals(Object object2) {
if (!(object2 instanceof Shape)) return false;
Shape shape2 = (Shape) object2;
return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
}
}

public class Circle extends Shape {
public int radius;

public Circle() {
}

public Circle(Circle target) {
super(target);
if (target != null) {
this.radius = target.radius;
}
}

@Override
public Shape clone() {
return new Circle(this);
}

@Override
public boolean equals(Object object2) {
if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
Circle shape2 = (Circle) object2;
return shape2.radius == radius;
}
}

public class Rectangle extends Shape {
public int width;
public int height;

public Rectangle() {
}

public Rectangle(Rectangle target) {
super(target);
if (target != null) {
this.width = target.width;
this.height = target.height;
}
}

@Override
public Shape clone() {
return new Rectangle(this);
}

@Override
public boolean equals(Object object2) {
if (!(object2 instanceof Rectangle) || !super.equals(object2)) return false;
Rectangle shape2 = (Rectangle) object2;
return shape2.width == width && shape2.height == height;
}
}

import java.util.ArrayList;
import java.util.List;

public class Demo {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
List<Shape> shapesCopy = new ArrayList<>();

Circle circle = new Circle();
circle.x = 10;
circle.y = 20;
circle.radius = 15;
circle.color = "red";
shapes.add(circle);

Circle anotherCircle = (Circle) circle.clone();
shapes.add(anotherCircle);

Rectangle rectangle = new Rectangle();
rectangle.width = 10;
rectangle.height = 20;
rectangle.color = "blue";
shapes.add(rectangle);

cloneAndCompare(shapes, shapesCopy);
}

private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) {
for (Shape shape : shapes) {
shapesCopy.add(shape.clone());
}

for (int i = 0; i < shapes.size(); i++) {
if (shapes.get(i) != shapesCopy.get(i)) {
System.out.println(i + ": Shapes are different objects (yay!)");
if (shapes.get(i).equals(shapesCopy.get(i))) {
System.out.println(i + ": And they are identical (yay!)");
} else {
System.out.println(i + ": But they are not identical (booo!)");
}
} else {
System.out.println(i + ": Shape objects are the same (booo!)");
}
}
}
}

Limitation

Reference