Overview: take an object as a prototype and clone multiple new instances similar to the prototype type by copying it. The prototype object can generate its own completed copy, because objects of the same class can access each other's private member variables.
1. Advantages and disadvantages
1). advantage:
- Java's own prototype mode is based on the replication of memory binary stream, which is better in performance than directly new an object.
- You can use deep cloning to save the state of the object, and use prototype mode to copy the object and save its state, which simplifies the process of creating the object, so that it can be used when needed, and can assist in the implementation of undo operation.
2). Disadvantages:
- Cloning complex objects with circular references can be cumbersome.
2. Application scenario
- If you need to copy some objects and want the code to be independent of the specific class to which these objects belong, you can use the prototype pattern.
- If subclasses differ in how their objects are initialized, you can use this pattern to reduce the number of subclasses. Others may create these subclasses to create specific types of objects.
- In prototype mode, you can use a series of pre generated objects of various types as prototypes.
3. Implementation method (java)
The clonable interface in Java is an immediately available prototype pattern.
Next, how to implement the prototype pattern without using the standard clonable interface.
1) Shape list
Universal shape interface
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); } }
circular
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; } }
rectangle
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; } }
Clone example
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!)"); } } } }
2) cache
Prototype registration station
Create a prototype factory that contains a series of predefined prototype objects. In this way, you can get a new object from the factory by passing the object name or other parameters. The factory will search for the appropriate prototype, clone and copy it, and finally return the copy to you.
Prototype factory
import java.util.HashMap; import java.util.Map; public class BundledShapeCache { private Map<String, Shape> cache = new HashMap<>(); public BundledShapeCache() { Circle circle = new Circle(); circle.x = 5; circle.y = 7; circle.radius = 45; circle.color = "Green"; Rectangle rectangle = new Rectangle(); rectangle.x = 6; rectangle.y = 9; rectangle.width = 8; rectangle.height = 10; rectangle.color = "Blue"; cache.put("Big green circle", circle); cache.put("Medium blue rectangle", rectangle); } public Shape put(String key, Shape shape) { cache.put(key, shape); return shape; } public Shape get(String key) { return cache.get(key).clone(); } }
demo example
public class Demo { public static void main(String[] args) { BundledShapeCache cache = new BundledShapeCache(); Shape shape1 = cache.get("Big green circle"); Shape shape2 = cache.get("Medium blue rectangle"); Shape shape3 = cache.get("Medium blue rectangle"); if (shape1 != shape2 && !shape1.equals(shape2)) { System.out.println("Big green circle != Medium blue rectangle (yay!)"); } else { System.out.println("Big green circle == Medium blue rectangle (booo!)"); } if (shape2 != shape3) { System.out.println("Medium blue rectangles are two different objects (yay!)"); if (shape2.equals(shape3)) { System.out.println("And they are identical (yay!)"); } else { System.out.println("But they are not identical (booo!)"); } } else { System.out.println("Rectangle objects are the same (booo!)"); } } }