The definition of prototype patterns :
A prototype pattern refers to a prototype instance that specifies the type of object to be created , And create new objects by copying these prototypes , It belongs to the creative design pattern . The core of the prototype pattern is to replicate the prototype object .
With an object prototype that already exists in the system , Copy directly from memory binary stream , No need to go through the time-consuming process of object initialization , Performance will be greatly improved .
Application scenario of prototype mode :
- It costs a lot to create objects , Need to optimize resources .
- Creating an object requires tedious data preparation or permission access , Need to improve performance or security .
- This kind of object is widely used in the system , And each caller needs to reassign its properties .
analysis JDK Shallow clone API The problems brought about by :
stay java Provided API in , There is no need to manually create an abstract prototype interface ,java Built in Cloneable Abstract prototype interface , Custom types only need to implement the interface and override Object.clone The method can be completed
A reproduction of this class .
By looking at JDK Source code discovery for , Actually Cloneable Is an empty interface .java The reason for offering Cloneable Interface , Just to notify at run time java Virtual machines can be safely used on this class clone
Method . If not Cloneable Interface , call clone() Method will throw CloneNotSupportedException abnormal .
If you use clone() Method , The following conditions need to be met :
- For any object o, There are o.clone() != o, In other words, the cloned object and the original object are not the same object .
- For any object o, There are o.clone().getClass() == o.getClass(), In other words, the cloned object is of the same type as the original object .
- For any object o, Should have o.clone().equals(o) establish , Why is this not absolute , Because if you don't rewrite hashcode and equals Under the circumstances , There is no guarantee of two objects equals equal .
So in java What's the problem with medium to shallow cloning , See the following example :
Create a User class , And rewrite clone Method :
package com.liuyi.designmode.creational.prototype; import lombok.Data; import java.util.List; /** * @ClassName User * @description: * @author:liuyi * @Date:2020/11/11 20:55 */ @Data public class User implements Cloneable{ private Integer id; private String name; private List<String> phoneList; /* * * @Author liuyi * @Description //TODO Rewrite the shallow cloning method * @Date 2020/11/11 21:11 * @Param [] * @return com.liuyi.designmode.creational.prototype.User **/ @Override protected User clone(){ try { return (User) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } }
Create an object , And then clone an object , Then modify the corresponding attribute value :
package com.liuyi.designmode.creational.prototype; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @ClassName PrototypeTest * @description: * @author:liuyi * @Date:2020/11/11 21:04 */ public class PrototypeTest { public static void main(String[] args) { // Create objects User user = new User(); user.setId(1); user.setName(" that "); List<String> PhoneList = new ArrayList<>(); PhoneList.add("1457697"); PhoneList.add("545452"); PhoneList.add("5155445645"); user.setPhoneList(PhoneList); // Print the previous object information System.out.println(user); // Clone objects User clone = user.clone(); // modify id by 2 clone.setId(2); // Delete list A value of the object clone.getPhoneList().remove(1); // Print respectively System.out.println(user); System.out.println(clone); } }
Let's look at the execution results :
You can see , I modified the cloned values , Basic data type id Changed the , It doesn't affect the original object , But change the reference type List, Then the value of the original object is changed . This is called shallow copy , This is also
The deadliest problem with shallow cloning . So how to solve this problem , Deep cloning can solve this problem .
Deep cloning using serialization :
Add a deepClone() Method , The code is as follows :
/* * * @Author liuyi * @Description A deep clone * @Date 2020/11/11 21:40 * @Param [] * @return com.liuyi.designmode.creational.prototype.User **/ public User deepClone(){ try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (User)ois.readObject(); }catch (Exception e){ e.printStackTrace(); return null; } }
hold clone Method modified to deepClone The results of this method are as follows :
This modification does not affect the original object , We have achieved our goal .
Advantages of prototype pattern :
- java The built-in prototype pattern is based on the replication of memory binary streams , In terms of performance, it is more direct than new One object is better .
- You can use deep cloning to save the state of an object , To use when needed , For example, the history of restoration, a certain state , Can assist in undo operations .
Disadvantages of the prototype pattern :
- You need to override clone Method to achieve .
- clone Inside the class , Modify if necessary , You need to modify the code , Against the principle of opening and closing .
- When it comes to deep cloning , You need to write complex code , And when objects are nested multiple times , Deep cloning is required for every layer of objects , It's more difficult to realize .