Prototype Pattern)
Finally, CSDN was chosen to sort out the knowledge points published over the past few years. This article was migrated to CSDN in parallel. Because CSDN also supports the MarkDown syntax, it's awesome!
Overview
The prototype mode is a creation design mode. It copies an existing instance to return a new instance, instead of creating a new instance. The copied instance is what we call the prototype, which can be customized. The prototype mode is used to create complex or time-consuming instances. In this case, copying an existing instance can make the program run more efficiently or create equal values, only similar data with different names.
The prototype mode requires that the object implement an interface that can "clone" itself, so that you can create a new instance by copying an instance object itself. In this way, you no longer need to care about the type of the instance when creating new objects through the prototype instance. As long as you implement the clone method, you can use this method to obtain new objects, instead, you do not need to create it through new.
Core
Concept:Use a prototype instance to specify the type of the object to be created and copy the prototype to create a new object. The prototype mode is an object creation mode.
Classification of representations:
Simple Registration Form
The two forms are only the implementation of the prototype mode.
Important:
An important core module of a simple prototype structure:
(Client) customer role
The customer class initiates a request to create an object.
(Prototype) Abstract Prototype role
This is an abstract role, usually implemented by a Java interface or a Java Abstract class. This role provides all the interfaces required for the specific prototype class.
(Concrete Prototype) Specific Prototype role
The Copied object. This role must implement the interface required by the abstract prototype role.
PrototypeManager
This role is used to create objects of a specific prototype and record each created object.
An important core module of the Registration Form prototype structure:
(Client) customer role
The customer class initiates a request to create an object.
(Prototype) Abstract Prototype role
This is an abstract role, usually implemented by a Java interface or a Java Abstract class. This role provides all the interfaces required for the specific prototype class.
(Concrete Prototype) Specific Prototype role
The Copied object. This role must implement the interface required by the abstract prototype role.
PrototypeManager
This role is used to create objects of a specific prototype and record each created object.
Use Cases
In resource optimization scenarios, class initialization consumes a lot of resources, including data and hardware resources.
For scenarios with performance and security requirements, using new to generate an object requires tedious data preparation or access permissions, you can use the prototype mode.
In the scenario where one object has multiple modifier, one object needs to be provided to other objects for access, and each caller may need to modify its value, you can consider using the prototype mode to copy multiple objects for callers.
In actual projects, the prototype mode rarely exists independently. It usually appears together with the factory method mode. Create an object by using the clone method and then provide it to the caller by the factory method. The prototype has been integrated with Java.
Program ape instance
Simple prototype modeThe following code is written and implemented in strict accordance with the three elements of the prototype in the preceding simple form, which is a basic structure representation.
Package yanbober. github. io; // abstract prototype role interface IPrototype {Object clones ();} // specify the prototype role class ConcretePrototypeLowImpl implements IPrototype {@ Override public Object clones () {IPrototype iPrototype = new role (); return iPrototype ;}} class implements IPrototype {@ Override public Object clones () {IPrototype iPrototype = new role (); return iPrototype ;}} // client role public class Main {public static void main (String [] args) {IPrototype iPrototype = new ConcretePrototypeLowImpl (); for (int index = 0; index <20; index ++) {ConcretePrototypeLowImpl clone = (ConcretePrototypeLowImpl) iPrototype. clones ();} iPrototype = new ConcretePrototypeHighImpl (); for (int index = 0; index <20; index ++) {ConcretePrototypeHighImpl clone = (ConcretePrototypeHighImpl) iPrototype. clones ();}}}
Registration Form prototypeThe following code is written and implemented in strict accordance with the four elements of the prototype pattern registered above, which is a basic structure representation.
Package yanbober. github. io; import java. util. hashMap; import java. util. map; // abstract prototype role interface IPrototype {Object clones (); void setTemp (String temp); String getTemp (); void print ();} // The specific prototype role class ConcretePrototypeLowImpl implements IPrototype {private String mTemp; @ Override public Object clones () {IPrototype iPrototype = new ConcretePrototypeLowImpl (); iPrototype. setTemp (mTemp); return iPrototype;} @ Override public void setTemp (String temp) {this. mTemp = temp;} @ Override public String getTemp () {return this. mTemp ;}@ Override public void print () {System. out. println ("ConcretePrototypeLowImpl #" + this. hashCode () + "# temp =" + this. mTemp) ;}} class ConcretePrototypeHighImpl implements IPrototype {private String mTemp; @ Override public Object clones () {IPrototype iPrototype = new ConcretePrototypeHighImpl (); iPrototype. setTemp (mTemp); return iPrototype;} @ Override public void setTemp (String temp) {this. mTemp = temp;} @ Override public String getTemp () {return this. mTemp ;}@ Override public void print () {System. out. println ("ConcretePrototypeHighImpl #" + this. hashCode () + "# temp =" + this. mTemp) ;}// prototype manager role class PrototypeManager {private static Map
Keymap = new HashMap <> (); private PrototypeManager () {// null} public synchronized static void setPrototype (String key, IPrototype value) {keymap. put (key, value);} public synchronized static IPrototype getPrototype (String key) {IPrototype iPrototype = keymap. get (key); if (iPrototype = null) {throw new IllegalArgumentException ("Can't find your key in the manager map! ");} Return iPrototype;} public synchronized static void removePrototype (String key) {keymap. remove (key) ;}// client role public class Main {public static void main (String [] args) {IPrototype iPrototype = new ConcretePrototypeLowImpl (); iPrototype. print (); PrototypeManager. setPrototype ("iPrototype", iPrototype); IPrototype clone = (IPrototype) PrototypeManager. getPrototype ("iPrototype "). clones (); clo Ne. setTemp ("clone step 1! "); Clone. print (); iPrototype = new ConcretePrototypeHighImpl (); iPrototype. print (); PrototypeManager. setPrototype ("iPrototype", iPrototype); clone = (IPrototype) PrototypeManager. getPrototype ("iPrototype "). clones (); clone. setTemp ("clone step 2! "); Clone. print (); PrototypeManager. removePrototype (" iPrototype ");}}
The running result is as follows:
ConcretePrototypeLowImpl #1163157884 # temp = null
ConcretePrototypeLowImpl #1956725890 # temp = clone step 1!
ConcretePrototypeHighImpl #356573597 # temp = null
ConcretePrototypeHighImpl #1735600054 # temp = clone step 2!
Code reflection:The prototype of simple form and registration form has its own strengths and weaknesses. If the number of prototype objects to be created is small and relatively fixed, the first form can be used. In this case, the reference of the prototype object can be saved by the client. If the number of prototype objects to be created is not fixed, the second form can be used. In this case, the client does not save the reference to the prototype object. This task is handed over to the Administrator object. Before copying a prototype object, the client can check whether the Administrator object already has a prototype object that meets the requirements. If yes, you can directly obtain this object reference from the Administrator class; if not, the client needs to copy this prototype object on its own.
Prototype mode provided in Java
Protected Object clone () method of Object Class
Java's Object class provides the protected Object clone () method to copy objects. subclasses can also replace this method to meet their own needs. There is a basic problem in copying objects, that is, objects usually reference other objects. When you use the clone () method of the Object class to copy an Object, the reference of this Object to other objects will also be copied.
Cloneable Interface
The Cloneable interface provided by Java only plays a role, that is, to notify the Java Virtual Machine during runtime that the clone () method can be safely used in this class. You can copy an object by calling this clone () method. Because the Object class itself does not implement the Cloneable interface, if the class to be considered does not implement the Cloneable interface, the CloneNotSupportedException exception will be thrown when the clone () method is called.
Basic conditions for Java cloning
The clone () method copies an object and returns it to the caller. Therefore, the clone () method must meet the following requirements:
For any object OBJ, there are: OBJ. clone ()! = OBJ. In other words, the cloned object is not the same as the original object.
For any object OBJ, there are: OBJ. clone (). getClass () = OBJ. getClass (). In other words, the cloned object is of the same type as the original object.
If the equals () method of object OBJ is defined as appropriate, OBJ. clone (). equals (OBJ) should be true.
In JAVA APIs, all classes that provide the clone () method satisfy the preceding conditions. JAVA designers should abide by three conditions when designing their own clone () methods. In general, the first two of the above three conditions are required, and the third is optional.
Java shortest cloning and deep cloning
Whether you implement the cloning method by yourself or use the cloning method provided by Java, there is a problem of shortest cloning and deep cloning.
Shortest clone
Only responsible for cloning the data passed by value (such as the basic data type and a special String type), rather than copying the referenced object, in other words, all references to other objects still point to the original object.
Deep clone
In addition to cloning the value to be cloned, the data of the reference type is also cloned. Variables that reference other objects will point to new objects that have been copied, instead of the original referenced objects. In other words, deep cloning copies all the objects referenced by the objects to be copied, and copying the referenced objects is called indirect replication.
It is difficult to determine how many layers should be deep for deep cloning. When you decide to copy an object in the form of deep cloning, you must decide whether to clone the objects indirectly or to continue using the deep cloning. Therefore, when using deep cloning, it is necessary to determine the depth. In addition, loop references may occur during the process of deep cloning, so you must be careful with the issue.
Notes
Copying objects in prototype mode implemented using Java APIs does not call the class constructor. Because the Object replication is completed by calling the Object class clone method, it directly copies data in the memory, so it does not call the class constructor. Not only will the code in the constructor not be executed, but even the access permission is invalid for the prototype. Do you still remember the singleton mode? In Singleton mode, you only need to set the access permission of the constructor method to private. However, the clone method directly ignores the constructor permission. Therefore,The Singleton mode conflicts with the prototype mode. Pay special attention to this mode during use.
Use the template provided by Java to design the prototype
There are two main points for prototype classes to implement prototype mode using APIs provided by Java:
Implement the Cloneable Interface
There is a Cloneable interface in java, which has only one function. It notifies virtual machines at runtime that they can safely use the clone method in the class implementing this interface. In a Java virtual machine, only classes that implement this interface can be copied. Otherwise, a CloneNotSupportedException exception will be thrown during runtime.
Override the clone method in the Object class
In Java, the parent class of all classes is an Object class, and the Object class has a clone method to return a copy of the Object, but its scope of the protected type, the general class cannot be called, therefore, the Prototype class must modify the clone method scope to the public type.
Code practice
The following is a prototype implemented using Java APIs:
package yanbober.github.io;class IPrototype implements Cloneable { public IPrototype clone(){ IPrototype prototype = null; try{ prototype = (IPrototype)super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return prototype; }}class ConcretePrototypeImpl extends IPrototype{ public void print(){ System.out.println("I'm Impl!!!"); }}public class Main { public static void main(String[] args){ ConcretePrototypeImpl cp = new ConcretePrototypeImpl(); for(int i=0; i< 100; i++){ ConcretePrototypeImpl clonecp = (ConcretePrototypeImpl)cp.clone(); clonecp.print(); } }}
Summary
The prototype has the following advantages:
When creating a new object instance is complex, you can use the prototype mode to simplify the object creation process. Copying an existing instance can improve the efficiency of creating a new instance. Good scalability. In the prototype mode, the abstract prototype class is provided and can be programmed on the client for the abstract prototype class. The object state can be saved by means of deep cloning, and the object state can be copied and saved in prototype mode, it can be used as needed (such as restoring to a certain historical State) to assist in undo operations.
Disadvantages of the prototype mode are as follows:
You need to configure a clone method for each class, And the clone method is located inside a class. When modifying an existing class, you need to modify the source code, which violates the "Open and Close principle ". Complex code is required for deep cloning. When multiple nested references exist between objects, in order to achieve deep cloning, the classes corresponding to each layer of objects must support deep cloning, it may be difficult to implement.