Design pattern - prototype pattern

Prototype mode (Prototype Pattern) is used to create duplicate objects while ensuring performance. This type of design pattern belongs to the creation pattern, which provides the best way to create objects. This pattern implements a prototype interface, which is used to create clones 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 necessary to reduce database calls

introduce

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 code: 1. Implement 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 examples: 1. Cell division. 2. Object clone() method in JAVA.

Advantages: 1. Improved performance. 2. Escape constructor constraints.

Disadvantages: 1. It is necessary to comprehensively consider the functions of the class when configuring the cloning method, which is not very difficult for new classes, but it is not necessarily easy for existing classes, 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.

realization

 

//Create an abstract class that implements the clonable interface
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;
   }
}

//Create an entity class that extends the above abstract class
public class Square extends Shape {
   public Square(){
     type = "Square";
   }
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle extends Shape {
   public Circle(){
     type = "Circle";
   }
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

//Create a class, get entity classes from the database, and store them in a 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);
   }
}

//PrototypePatternDemo uses the ShapeCache class to get clones of shapes stored in Hashtable
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());             
   }
}

Keywords: Java Design Pattern

Added by sidney on Wed, 22 Dec 2021 02:10:49 +0200