Definition: prototype pattern is to use prototype instances to specify the type of objects to be created, and to create new objects by copying these prototypes.
In the application program, some objects are more complex, and the creation process is too complex, and we need to use the object frequently. If we new the object according to the conventional thinking at this time, it must cause waste of resources. At this time, we hope that we can use an existing object to copy it continuously, which is the "clone" in programming " The prototype mode directly operates the underlying binary stream, and the efficiency of creating complex objects is significantly improved.
UML class diagram:
Shallow clone and deep clone:
Shallow clone: when the prototype object is copied, only the member variables of its own and the contained value type are copied, while the member variables of the reference type are not copied.
Deep clone: in addition to the object itself being copied, all member variables contained in the object will also be copied.
Shallow clones:
public class Person implements Cloneable { private String name; private boolean gender; private Interest interest; public Person(String name, boolean gender, Interest interest) { this.name = name; this.gender = gender; this.interest = interest; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isGender() { return gender; } public void setGender(boolean gender) { this.gender = gender; } public Interest getInterest() { return interest; } public void setInterest(Interest interest) { this.interest = interest; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", gender=" + gender + ", interest=" + interest + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Interest interest = new Interest("Photography"); Person gg = new Person("gg",false,interest); System.out.println(gg); Person dxy = (Person)gg.clone(); dxy.setName("dxy"); dxy.setGender(true); dxy.interest.setName("Coffee"); System.out.println(dxy); System.out.println(gg); } } class Interest{ private String name; public Interest(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Interest{" + "name='" + name + '\'' + '}'; } }
Operation result:
Person} Person} Person}
Shallow clone for reference type, only the reference is cloned. Therefore, the interest of two objects share the same memory address. If one object changes, the response of the other object will change.
Deep cloned:
public class Person implements Cloneable { private String name; private boolean gender; private Interest interest; public Person(String name, boolean gender, Interest interest) { this.name = name; this.gender = gender; this.interest = interest; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isGender() { return gender; } public void setGender(boolean gender) { this.gender = gender; } public Interest getInterest() { return interest; } public void setInterest(Interest interest) { this.interest = interest; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", gender=" + gender + ", interest=" + interest + '}'; } @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone(); //Call the clone() method of the object object directly! //Add the following code to realize deep clone Person person = (Person) obj; person.interest = (Interest)this.interest.clone(); //Clone the attribute too! return obj; } public static void main(String[] args) throws CloneNotSupportedException { Interest interest = new Interest("Photography"); Person gg = new Person("gg",false,interest); System.out.println(gg); Person dxy = (Person)gg.clone(); dxy.setName("dxy"); dxy.setGender(true); dxy.interest.setName("Coffee"); System.out.println(dxy); System.out.println(gg); } } class Interest implements Cloneable { private String name; public Interest(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Interest{" + "name='" + name + '\'' + '}'; } }
Operation result:
Person} Person} Person}
By adding the clone method to the reference type value Interest and modifying the clone method of the Person object, the deep clone is realized.
In addition, deep replication can be realized through serialization and deserialization.
public class Person implements Serializable { private String name; private boolean gender; private Interest interest; public Person(String name, boolean gender, Interest interest) { this.name = name; this.gender = gender; this.interest = interest; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isGender() { return gender; } public void setGender(boolean gender) { this.gender = gender; } public Interest getInterest() { return interest; } public void setInterest(Interest interest) { this.interest = interest; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", gender=" + gender + ", interest=" + interest + '}'; } public static void main(String[] args) throws CloneNotSupportedException,ClassNotFoundException,IOException { Interest interest = new Interest("Photography"); Person gg = new Person("gg",false,interest); System.out.println(gg); //Deep replication using serialization and deserialization ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(gg); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); Person dxy = (Person) ois.readObject(); //Cloned object! dxy.interest.setName("Coffee"); System.out.println(dxy); System.out.println(gg); } } class Interest implements Serializable{ private String name; public Interest(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Interest{" + "name='" + name + '\'' + '}'; } }
Operation result:
Person} Person} Person}
Advantage:
When it is more complex to create an object instance, using prototype mode can simplify the object creation process.
Direct operation of binary streams can improve the efficiency of instance creation.
Disadvantages:
It is necessary to configure a clone method for each class, and the clone method is located inside the class. When modifying the existing class, the code needs to be modified, which violates the open and close principle.
In order to realize deep cloning, the classes corresponding to each layer of objects must support deep cloning, which will be more difficult to implement.
In addition, when the clone object is used, the constructor is not called and the permission of the constructor is ignored.