1. Prototype mode
Prototype Pattern is used to create duplicate objects while ensuring performance. This type of design pattern is a creation pattern, which provides the best way to create objects.
This pattern implements a prototype interface that is used to create a clone of the current object. This pattern is used when the cost of directly creating objects is relatively high. For example, an object needs to be created after a costly database operation. We can cache the object, return its clone on the next request, and update the database when needed to reduce database calls.
2. Introduction
Intent: use prototype instances to specify the kind of objects to create, and create new objects by copying these prototypes.
The main solution is to create and delete prototypes during operation.
When to use:
1. When a system should be created, composed and represented independently of its products. 2. When the class to be instantiated is specified at run time, for example, through dynamic loading.
3. To avoid creating a factory class hierarchy parallel to the product class hierarchy. 4. When an instance of a class can only have one of several different state combinations. It may be more convenient to build a corresponding number of prototypes and clone them than to manually instantiate the class with the appropriate state each time.
How to solve: use an existing prototype object to quickly generate the same instance as the prototype object.
Key codes:
1. To implement the cloning operation, inherit clonable in JAVA and rewrite clone() NET, you can use the MemberwiseClone() method of the Object class to realize the shallow copy of the Object or the deep copy by serialization.
2. The prototype pattern is also used to isolate the coupling relationship between the users of class objects and specific types (mutable classes). It also requires these "mutable classes" to have stable interfaces.
Application example:
1. Cell division.
2. Object clone() method in JAVA.
advantage:
1. Improved performance.
2. Escape constructor constraints.
Disadvantages:
1. It is not very difficult for a new class, but it is not necessarily easy for an existing class, especially when a class references indirect objects that do not support serialization, or references contain circular structures.
2. The clonable interface must be implemented.
Usage scenario:
1. Resource optimization scenario.
2. Class initialization needs to digest a lot of resources, including data, hardware resources, etc.
3. Scenarios with performance and safety requirements.
4. If generating an object through new requires very cumbersome data preparation or access rights, you can use the prototype pattern.
5. A scene where one object has multiple modifiers.
6. When an object needs to be accessed by other objects, and each caller may need to modify its value, you can consider using the prototype pattern to copy multiple objects for the caller to use.
7. In actual projects, the prototype pattern rarely appears alone. It usually appears together with the factory method pattern. An object is created through the clone method, and then provided to the caller by the factory method. The prototype pattern has been integrated with Java, and you can use it easily.
Note: unlike instantiating a class to construct a new object, the prototype pattern generates a new object by copying an existing object. Shallow copy implements clonable, rewriting, and deep copy reads binary streams by implementing Serializable.
3. Realization
We will create an abstract class shape and an entity class that extends the shape class. The next step is to define the class ShapeCache, which stores shape objects in a Hashtable and returns their clones when requested.
The PrototypePatternDemo class uses the ShapeCache class to get Shape objects.
- Step 1
Create an abstract class that implements the clonable interface.
Shape.java public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }
Step 2
Create an entity class that extends the above abstract class.
Rectangle.java public class Rectangle extends Shape { public Rectangle(){ type = "Rectangle"; } @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }
Square.java public class Square extends Shape { public Square(){ type = "Square"; } @Override public void draw() { System.out.println("Inside Square::draw() method."); } }
Circle.java public class Circle extends Shape { public Circle(){ type = "Circle"; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
- Step 3
Create a class, get entity classes from the database, and store them in a Hashtable.
ShapeCache.java import java.util.Hashtable; public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } // Run a database query on each shape and create the shape // shapeMap.put(shapeKey, shape); // For example, we want to add three shapes public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(),rectangle); } }
- Step 4
PrototypePatternDemo uses the ShapeCache class to get clones of shapes stored in Hashtable.
PrototypePatternDemo.java public class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } }