Definition of prototype mode
Prototype pattern is second only to singleton mode and iterator mode. It is because of its simplicity that many scenarios are used. Its definition is as follows:
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.Use a prototype instance to specify the type of the object to be created, and copy the prototype to create a new object.
The general class diagram of the prototype mode is as follows.
Simple and simple. The core of the prototype mode is a clone method that copies objects. Java provides a cloneable interface to indicate that this object can be copied, why is it "mark? Open the JDK to help you see that cloneable does not have a method. This interface is only a tag. Only objects with this tag in JVM can be copied, then how can we convert from "may be copied" to "can be copied? The method overwrites the clone () method. Yes, you do not see the error of rewriting the clone () method. Let's look at the clone method in the mail class above, as shown below.
@ Overridepublic mail clone (){}
Readers should note that an annotation @ override is added to the clone () method. Why can this annotation be overwritten without inheriting a class? Think about it. Who is the ancestor of all classes in Java? Yes, the object class. By default, each class inherits this class. Therefore, it is very correct to use overwriting. -- override the clone method in the object class!
The original model in Java is so simple.Source code, As shown below.
Public class prototypeclass implements cloneable {// override the parent class Object method @ overridepublic prototypeclass clone () {prototypeclass = NULL; try {prototypeclass = (prototypeclass) super. clone ();} catch (clonenotsupportedexception e) {// Exception Handling} return prototypeclass ;}}
Implement an interface and rewrite the clone method to complete the prototype!
Application of Prototype
Advantages of Prototype
◇ Excellent performance
The prototype mode is to copy binary streams in the memory, which has much better performance than a new object, especially when a large number of objects are generated in a loop, the prototype can better reflect its advantages.
◇ Escape constructor Constraints
This is both an advantage and a disadvantage. The constructor does not execute the constructor directly in the memory (see "precautions for prototype mode"). The advantage is that the constraints are reduced, the disadvantage is that it reduces constraints and is a double-edged sword, which needs to be considered in actual application.
Use Cases of Prototype
◇ Resource Optimization scenarios
Class initialization needs to digest a lot of resources, including data and hardware resources.
◇ Scenarios with performance and security requirements
To generate an object through new requires tedious data preparation or access permissions, you can use the prototype mode.
◇ Scenario of multiple modifier of an object
When an object needs to be accessed by other objects and each caller may need to modify its value, you can consider copying multiple objects in prototype mode for the caller to use.
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 and can be easily used.
Precautions for prototype mode
Although the prototype mode is very simple, there are still some precautions for using the prototype mode, namely the clone method, in Java. We will explain it one by one through several examples (if you are not familiar with Java, you can open the following sections ).
The constructor will not be executed.
A Class A that implements cloneable and overrides the clone method. Class A has a no-argument structure or a parameter to construct B. An object S is generated through the New Keyword, and then through S. the clone () method generates a new object T, so constructor B will not be executed during object copying. Let's write a short section.ProgramTo illustrate this problem, as shown below.
Public class thing implements cloneable {public thing () {system. out. println ("the constructor is executed... ") ;}@ overridepublic thing clone () {thing = NULL; try {thing = (thing) super. clone ();} catch (clonenotsupportedexception e) {e. printstacktrace () ;}return thing ;}then Let's write a client class to copy the object, as shown below.
Public class client {public static void main (string [] ARGs) {// generate an object thing = new thing (); // copy an object thing clonething = thing. clone ();}}
The running result is as follows.
The constructor is executed...
The constructor is indeed not executed during object copying. This can also be explained in principle. The clone method of the object class is based on the memory (specifically the heap memory) if you copy a binary stream and re-allocate a memory block, it is normal that the constructor is not executed.
Shortest copy and deep copy
Let's take a look at the example before explaining what is a shallow copy or a deep copy, as shown below.
Public class thing implements cloneable {// defines a private variable private arraylist <string> arraylist = new arraylist <string> (); @ overridepublic thing clone () {thing = NULL; try {thing = (thing) super. clone ();} catch (clonenotsupportedexception e) {e. printstacktrace ();} return thing;} // set the value of hashmap public void setvalue (string value) {This. arraylist. add (value) ;}// obtain the value of arraylist public arraylist <string> getvalue () {return this. arraylist ;}}
Add a private variable arraylis to the thing class, whose type is arraylist. Then, set and set the value through setvalue and getvalue respectively. Let's see how the scenario class is copied, as shown below.
Public class client {public static void main (string [] ARGs) {// generates an object thing = new thing (); // sets a value thing. setvalue ("Zhang San"); // copy an object thing clonething = thing. clone (); clonething. setvalue ("Li Si"); system. out. println (thing. getvalue ());}}
What are the running results? Is it just a "Michael? The running result is as follows.
[Zhang San, Li Si]
How can this happen? Why is there Li Si? Let me explain it to you because Java has made a lazy copy action. The method clone provided by the object class only copies the current object, and its internal arrays and referenced objects are not copied, it still points to the internal element address of the native object. This kind of copy is called the shortest copy. It is really very shortest. The two objects share a private variable. You can change it if you change it, it is a very insecure method, but it is rarely used in actual projects (of course, it is also a life-saving method in a "crisis" environment ). You may be wondering why the string type can be used in the mail class without the problem caused by the shortest copy? Internal arrays and referenced objects are not copied. Other primitive types such as int, long, and string (Java wants you to think of string as the basic type, and string has no clone method) will be copied.
Note: When copying using the clone method, objects that meet two conditions will not be copied: one is the member variable of the class, not the variable in the method; the other is the object, not the original type.
It is risky to copy a copy. How can we copy it in depth? We can modify the program to make a deep copy, as shown below.
Public class thing implements cloneable {// defines a private variable private arraylist <string> arraylist = new arraylist <string> (); @ overridepublic thing clone () {thing = NULL; try {thing = (thing) super. clone (); thing. arraylist = (arraylist <string>) This. arraylist. clone ();} catch (clonenotsupportedexception e) {e. printstacktrace ();} return thing ;}}
Only the simhei part is added to copy private class variables independently. The client class has not changed. The running result is as follows.
[James]
This method implements a full copy, and there is no relationship between the two objects. You modify your, I modify my, and it does not affect each other. This copy is called a deep copy, another way to achieve deep copy is to operate on objects by writing binary streams by yourself, and then implement deep copy of objects. You have time to implement this on your own.
Note: We recommend that you do not mix deep copy and shallow copy. Especially when class inheritance is involved, it is very complicated for the parent class to have multiple references, the recommended solution is to separate the deep copy and the light copy.
Clone and final
As the saying goes, the object clone conflicts with the final keyword in the object. We will give an example to illustrate this problem, as shown below.
Public class thing implements cloneable {// defines a private variable private final arraylist <string> arraylist = new arraylist <string> (); @ overridepublic thing clone () {thing = NULL; try {thing = (thing) super. clone (); this. arraylist = (arraylist <string>) This. arraylist. clone ();} catch (clonenotsupportedexception e) {e. printstacktrace ();} return thing ;}}
Only a final keyword is added to the simhei part. Then the compiler will report an error in the Italic part. Normally, you still want to reset the final type! The final keyword is destroyed, and you have to realize the dream of deep copy. There is always a path. Let's think about how to modify this method: Delete the final keyword, this is the most convenient, secure, and fast way. Do not add the final keyword to the member variables of the class by using the clone method.
Note: To use the clone method, do not add the final keyword to the member variables of the class.
Summary
The prototype generates a class that contains a large amount of common information. Then, you can copy a copy, correct the details, and create a complete personalized object. I wonder if you have ever seen the movie "Sixth Day" played by Arnold. The main line of the movie is that a person is copied, and the original and copy are right-handed, the prototype model we are talking about today is the concept that one original can create multiple replicas. It can be understood as follows: the generation of an object can not start from scratch, directly clone an object that already has a certain prototype, and then repair it to produce the desired object. That is to say, to generate a person, you can not grow from 1 to 2 years old, then 3 years old ..., You can also directly find a person, get the DNA from it, and then clone it. modify it to be 30 years old !, The prototype model we are talking about is a feature that follows the trend of the times!