Document directory
- Registration Form prototype
- Comparison of Two Forms
The prototype mode belongs to the object creation mode. Specify the type of all created objects by providing a prototype object, and then create more objects of the same type by copying the prototype object. This is the intention of the prototype.
Prototype Structure
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.
The prototype has two forms: (1) Simple Form and (2) Registration Form. These two forms are only different implementations of the prototype.
Simple prototype mode
This form involves three roles:
(1) client role: the customer class initiates a request to create an object.
(2) prototype role: This is an abstract role, usually implemented by a Java interface or Java Abstract class. This role provides all the interfaces required for the specific prototype class.
(3) Concrete prototype role: the object to be copied. This role must implement the interfaces required by the abstract prototype role.
Source code
Abstract prototype role
Package COM. bankht. prototype;/*** @ Author: -AK47 * @ Creation Time: 03:58:33, December 25, ** @ Class description: abstract prototype role */public interface prototype {/*** method of cloning itself ** @ return a cloned object from itself */Public prototype clone ();}
Prototype role
Package COM. bankht. prototype;/*** @ Author: -AK47 * @ Creation Time: 03:59:15, December 25, ** @ Class description: specific prototype role */public class concreteprototype1 implements prototype {public prototype clone () {// The simplest clone, create a new object, prototype prototype = new concreteprototype1 (); Return prototype ;}}
Package COM. bankht. prototype;/*** @ Author: -AK47 * @ Creation Time: 03:59:15, December 25, ** @ Class description: specific prototype role */public class concreteprototype2 implements prototype {public prototype clone () {// The simplest clone, create a new object, prototype prototype = new concreteprototype2 (); Return prototype ;}}
Client role
Package COM. bankht. prototype; import Org. JUnit. test;/*** @ Author: -AK47 * @ Creation Time: 04:00:46, December 25, ** @ Class description: client role */public class client {@ testpublic void testprototype () {New testprototype (New concreteprototype1 ()). operation () ;}} class testprototype {/*** holds the required prototype interface object */Public prototype;/*** constructor, input the required prototype interface object */Public testprototype (prototype) {This. prototype = prototype;} public void operation () {// object of the prototype interface to be created: system. out. println ("the obtained prototype is:" + this. prototype. clone (). getclass (). getsimplename () + ". java ");}}
Running result:
The obtained prototype is concreteprototype1.java.
Registration Form prototype
As the second form of prototype mode, it has an additional prototypemanager role, which is used to create objects of a specific prototype and record each created object.
Source code
Abstract prototype role
Package COM. bankht. prototype. register;/*** @ Author: -AK47 * @ Creation Time: 04:53:29, December 25, ** @ Class description: abstract prototype role */public interface prototype {public prototype clone (); Public String getname (); Public void setname (string name );}
Prototype role
Package COM. bankht. prototype. register;/*** @ Author: -AK47 * @ Creation Time: 04:54:03, December 25, ** @ Class description: specific prototype role */public class concreteprototype1 implements prototype {private string name; Public prototype clone () {concreteprototype1 prototype = new concreteprototype1 (); Return prototype;} Public String tostring () {return "now in prototype1, name =" + this. name ;}@ overridepublic string getname () {return name ;}@ overridepublic void setname (string name) {This. name = Name ;}}
Package COM. bankht. prototype. register;/*** @ Author: -AK47 * @ Creation Time: 04:54:29, December 25, ** @ Class description: specific prototype role */public class concreteprototype2 implements prototype {private string name; Public prototype clone () {concreteprototype2 prototype = new concreteprototype2 (); Return prototype;} Public String tostring () {return "now in prototype2, name =" + this. name ;}@ overridepublic string getname () {return name ;}@ overridepublic void setname (string name) {This. name = Name ;}}
The role of the prototype manager maintains an aggregation. As a registration of all prototype objects, this role provides the necessary methods to add new prototype objects and obtain registered prototype objects.
Package COM. bankht. prototype. register; import Java. util. hashmap; import Java. util. map;/*** @ Author: -AK47 * @ Creation Time: 04:54:55, December 25, ** @ Class description: The Role of the prototype manager maintains a group, as a registration of all prototype objects, this role provides the necessary methods to add new prototype objects and obtain registered prototype objects. */Public class prototypemanager {/*** is used to record the correspondence between prototype numbers and prototype instances */Private Static Map <string, prototype> map = new hashmap <string, prototype> ();/*** private constructor to avoid external instance creation */private prototypemanager () {}/*** add or modify a prototype to the prototype manager ** @ Param prototypeid * Prototype number * @ Param prototype */Public synchronized static void setprototype (string prototypeid, prototype prototype) {map. put (prototypeid, prototype);}/*** delete a prototype registration from the prototype manager ** @ Param prototypeid * prototype ID */Public synchronized static void removeprototype (string prototypeid) {map. remove (prototypeid );} /*** obtain the prototype instance corresponding to a prototype number ** @ Param prototypeid * Prototype number * @ return Prototype number corresponding to the prototype instance * @ throws exception * If the Prototype number corresponds to the instance does not exist, throw an exception */Public synchronized static prototype getprototype (string prototypeid) throws exception {prototype = map. get (prototypeid); If (prototype = NULL) {Throw new exception ("the prototype you want to obtain is not registered or destroyed");} return prototype ;}}
Client role
Package COM. bankht. prototype. register;/*** @ Author: -AK47 * @ Creation Time: 04:55:39, December 25, ** @ Class description: client role */public class client {public static void main (string [] ARGs) {try {prototype p1 = new concreteprototype1 (); prototypemanager. setprototype ("p1", P1); // obtain the prototype to create the prototype P3 = prototypemanager. getprototype ("p1 "). clone (); p3.setname ("James"); system. out. println ("first instance:" + P3); // some people dynamically switch prototype P2 = new concreteprototype2 (); prototypemanager. setprototype ("p1", P2); // obtain the prototype again to create prototype P4 = prototypemanager. getprototype ("p1 "). clone (); p4.setname ("Li Si"); system. out. println ("second instance:" + P4); // someone canceled this prototypemanager. removeprototype ("p1"); // obtain the prototype again to create prototype P5 = prototypemanager. getprototype ("p1 "). clone (); p5.setname ("Wang Wu"); system. out. println ("third instance:" + P5);} catch (exception e) {e. printstacktrace ();}}}
Comparison of Two Forms
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.
Java cloning method
All Java classes are from Java. lang. the object class is inherited, and the object class provides the protected object clone () method to copy the object. The subclass can also replace this method and provide a copy method that meets your 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, this object will also be referenced by other objects.
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.
Cloning Conditions
The clone () method copies an object and returns it to the caller. The meaning of the so-called "copy" and how the clone () method are implemented. Generally, the clone () method meets the following requirements:
(1) for any object X, there are: X. Clone ()! = X. In other words, the cloned object is not the same as the original object.
(2) For any object X, X. Clone (). getclass () = x. getclass (). In other words, the cloned object is of the same type as the original object.
(3) If the equals () method of object X is defined as appropriate, X. Clone (). Equals (x) 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.
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.
Only responsible for cloning the data passed by value (such as the basic data type and string type), rather than copying the object it references, in other words, all references to other objects still point to the original object.
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.
Deep cloning using serialization
The process of writing an object to a stream is a serialization process, while the process of reading the object from the stream is called the deserialization process. It should be noted that a copy of the object is written to the stream, and the original object still exists in JVM.
To clone an object in depth in Java, You can first implement the serializable interface for the object, and then write the object (actually just copying the object) to a stream (serialization ), then, the object can be re-built by reading back from the stream (deserialization.
Public object deepclone () throws ioexception, classnotfoundexception {// write the object to bytearrayoutputstream Bos = new bytearrayoutputstream (); objectoutputstream OOS = new objectoutputstream (BOS); OOS. writeobject (this); // read bytearrayinputstream Bis = new bytearrayinputstream (Bos. tobytearray (); objectinputstream OIS = new objectinputstream (bis); Return Ois. readobject ();}
The premise is that the object and all referenced objects inside the object are serializable. Otherwise, you need to carefully check whether the non-serializable objects can be set to transient, in this way, it is excluded from the replication process.
Simple cloning is obviously easier to implement than deep cloning, because all classes in the Java language will inherit a clone () method, and the clone () method is a simple clone.
Some objects, such as thread objects or socket objects, cannot be simply copied or shared. Whether it is simple cloning or deep cloning, as long as such indirect objects are involved, the indirect objects must be set to transient instead of being copied; or the program creates a similar object by itself, and can be used as a copy.
Sun dasheng's external spells
What if Sun dasheng's external skills are implemented using the prototype in Java? First, the greatest sage class assumes the customer role. Qi tianda Sheng holds an example of a zookeeper (monkey), and a zookeeper is the original statue of the Great Sage. The monkey class has the clone () method inherited from Java. Lang. Object. Therefore, you can copy a monkey instance by calling this clone method.
Sun dasheng himself uses thegreatestsage class representatives
Public class thegreatestsage {private monkey = new monkey (); Public void change () {// clone the original monkey copymonkey = (monkey) monkey. clone (); system. out. println ("the birthday of the Grand saint is:" + monkey. getbirthdate (); system. out. println ("the birthday of the cloned dasheng is:" + monkey. getbirthdate (); system. out. println ("Whether the master is the same object as the cloned master" + (monkey = copymonkey); system. out. println ("is the golden hoop held by the Grand saint the same object as the golden hoop held by the cloned grand saint? "+ (Monkey. getstaff () = copymonkey. getstaff ();} public static void main (string [] ARGs) {thegreatestsage sage = new thegreatestsage (); Sage. change ();}}
Dasheng is represented by the monkey class. This class assumes the specific prototype role:
Public class monkey implements cloneable {// height private int height; // weight private int weight; // birthday private date birthdate; // golden hoop rod private goldringedstaff staff; /*** constructor */Public monkey () {This. birthdate = new date (); this. staff = new goldringedstaff ();}/*** clone method */public object clone () {monkey temp = NULL; try {temp = (monkey) super. clone ();} catch (clonenotsupportedexception e) {// todo auto-generated Catch Block E. printstacktrace ();} finally {return temp;} public int getheight () {return height;} public void setheight (INT height) {This. height = height;} public int getweight () {return weight;} public void setweight (INT weight) {This. weight = weight;} public date getbirthdate () {return birthdate;} public void setbirthdate (date birthdate) {This. birthdate = birthdate;} public goldringedstaff getstaff () {return staff;} public void setstaff (goldringedstaff staff) {This. staff = staff ;}}
Dasheng also holds an instance of a golden hoop, golden hoop category goldringedstaff:
Public class goldringedstaff {private float Height = 100366f; private float diameter = 10.0f;/*** increasing behavior: the length and radius of each call are doubled */Public void grow () {This. diameter * = 2; this. height * = 2;}/*** reduces the call length and radius by half. */Public void shrink () {This. diameter/= 2; this. height/= 2 ;}}
When running the thegreatestsage class, first create the object of the master object, and thenShortest cloneThe object of the Grand saint. The program prints the following information during running:
It can be seen that, first of all, the copied master has the same birthdate as the original master object, and the master object is not the same, which indicates that they are in a clone relationship. Second, the master's Master's master. This indicates that the golden hoop held by the two is one, not two.
As mentioned above, the clone () method inherited from the java. Lang. object class is a shortest clone. In other words, the reference of all the gimmicks held by the embodiment of Qi tianda saint all points to an object, which is not consistent with the description in Journey to the West. To correct this, you need to consider usingDeep clone.
To achieveDeep cloneAll objects to be copied must implement the java. Io. serializable interface.
Source code of Sun dasheng:
Public class thegreatestsage {private monkey = new monkey (); Public void change () throws ioexception, classnotfoundexception {monkey copymonkey = (monkey) monkey. deepclone (); system. out. println ("the birthday of the Grand saint is:" + monkey. getbirthdate (); system. out. println ("the birthday of the cloned dasheng is:" + monkey. getbirthdate (); system. out. println ("Whether the master is the same object as the cloned master" + (monkey = copymonkey); system. out. println Is the golden hoop held by dasheng the same object? "+ (Monkey. getstaff () = copymonkey. getstaff ();} public static void main (string [] ARGs) throws ioexception, classnotfoundexception {thegreatestsage sage = new thegreatestsage (); Sage. change ();}}
In the big holy book monkey class, there are two clone methods, one is clone (), that is, the shallow clone; the other is deepclone (), that is, deep clone. In the deep clone method, the object (a copy) of the Grand saint is serialized and then deserialized. The deserialization object becomes a deep clone result.
Public class monkey implements cloneable, serializable {// height private int height; // weight private int weight; // birthday private date birthdate; // golden hoop rod private goldringedstaff staff; /*** constructor */Public monkey () {This. birthdate = new date (); Staff = new goldringedstaff ();}/*** clone method */public object clone () {monkey temp = NULL; try {temp = (monkey) super. clone ();} catch (clonenotsupportedexception e) {// todo auto-generated Catch Block E. printstacktrace ();} finally {return temp;} public object deepclone () throws ioexception, classnotfoundexception {// write the object to the stream bytearrayoutputstream Bos = new bytearrayoutputstream (); objectoutputstream OOS = new objectoutputstream (BOS); OOS. writeobject (this); // read bytearrayinputstream Bis = new bytearrayinputstream (Bos. tobytearray (); objectinputstream OIS = new objectinputstream (bis); Return Ois. readobject () ;}public int getheight () {return height;} public void setheight (INT height) {This. height = height;} public int getweight () {return weight;} public void setweight (INT weight) {This. weight = weight;} public date getbirthdate () {return birthdate;} public void setbirthdate (date birthdate) {This. birthdate = birthdate;} public goldringedstaff getstaff () {return staff;} public void setstaff (goldringedstaff staff) {This. staff = staff ;}}
As you can see, the Grand saint has a goldringedstaff instance. In the big holy copy, this golden hoop is a copy of the Golden hoop object held by the original big holy copy object. When a grand Saint object is serialized and deserialized, the Golden Horse objects it holds are also serialized and deserialized at the same time, in this way, the master's Master's master.
Public class goldringedstaff implements serializable {private float Height = 100366f; private float diameter = 10.0f;/*** increasing behavior: the length and radius of each call are doubled */Public void grow () {This. diameter * = 2; this. height * = 2;}/*** reduces the call length and radius by half. */Public void shrink () {This. diameter/= 2; this. height/= 2 ;}}
From the running results, we can see that the golden hoop of dasheng is different from that of the outside. This is because the deep clone is used to copy the objects referenced by the Grand saint, including the golden hoop.
Advantages of Prototype
The prototype mode allows you to dynamically change the implementation type at runtime. During the running of the prototype mode, the customer can register the implementation types that conform to the prototype interface, or dynamically change the specific implementation types. It seems that the interface has not changed, however, another class instance is running. Because cloning a prototype is similar to instantiating a class.
Disadvantages of Prototype
The main disadvantage of the prototype mode is that each class must have a clone method. To assign a clone method, you need to consider the functions of the class comprehensively. This is not difficult for all new classes, but not necessarily easy for existing classes, especially when a class references indirect objects that do not support serialization or reference a circular structure.