1, Definition
Prototype Pattern: one of the innovative patterns, which uses prototype instances to specify the type of objects to be created, and creates new objects by copying these prototypes.
2, UML class diagram
3, Roles and responsibilities
- Prototype: declare an interface that clones itself.
- Concrete Prototype: it implements an operation of cloning itself.
- Client: the client lets a prototype object clone itself to create a new object.
4, Code implementation
Take chestnuts for example. Now we have created a new QQ number. We want to clone our friends on our old QQ number to the new QQ number. Then, the general code is as follows:
First create a QQ friend class
@AllArgsConstructor @Data public class QQFriend { /** * nickname */ private String nickname; /** * QQ number */ private String QQNo; }
Then we clone
public class PrototypeTest { public static void main(String[] args) { QQFriend qqFriend = new QQFriend("Cream cheese mushroom soup", "1706046690"); QQFriend clone = new QQFriend(qqFriend.getNickname(), qqFriend.getQQNo()); // Running result: false System.out.println(qqFriend == clone); } }
In this way, we need to obtain the properties of the original object every time we create a new object, which is very inefficient, and we can't dynamically obtain the runtime state of the object. If the properties of the original object change, we also need to change the code. For this, we can use the prototype pattern.
The prototype pattern can be divided into shallow copy and deep copy. The difference lies in the copy of member variables that reference data types.
-
Shallow copy: shallow copy only copies the pointer to an object, not the object itself. The old and new objects still share the same piece of memory.
Implement the clonable interface of the original QQ friend class, rewrite the clone() method, and add a QQ friend attribute
@AllArgsConstructor @Data public class QQFriend implements Cloneable { /** * nickname */ private String nickname; /** * QQ number */ private String QQNo; /** * QQ Friends */ private QQFriend qqFriend; public QQFriend(String nickname, String QQNo) { this.nickname = nickname; this.QQNo = QQNo; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
View run results
public class PrototypeTest { public static void main(String[] args) throws Exception { QQFriend qqFriend = new QQFriend("Cream cheese mushroom soup", "1706046690",new QQFriend("First sight","1415478419")); QQFriend clone = (QQFriend)qqFriend.clone(); // Running result: true System.out.println(qqFriend.getQqFriend() == clone.getQqFriend()); } }
Through the running results, it can be found that the shallow copy copies a new object through the clone() method, but the friend attribute address of the new object still points to the friend attribute address of the original object. If the attribute of the original object changes, the attribute of the new object will also change.
-
Deep copy: deep copy will create an identical object. The new object and the original object do not share memory. Modifying the new object will not change the original object.
We only need to modify the cloning attribute of QQ friend class and clone the QQ friend attribute of QQ friend class again when cloning.
@AllArgsConstructor @Data public class QQFriend implements Cloneable { /** * nickname */ private String nickname; /** * QQ number */ private String QQNo; /** * QQ Friends */ private QQFriend qqFriend; public QQFriend(String nickname, String QQNo) { this.nickname = nickname; this.QQNo = QQNo; } @Override protected Object clone() throws CloneNotSupportedException { QQFriend qqFriend = (QQFriend)super.clone(); if(this.getQqFriend() != null) qqFriend.setQqFriend((QQFriend)this.getQqFriend().clone()); return qqFriend; } }
View run results
public class PrototypeTest { public static void main(String[] args) throws Exception { QQFriend qqFriend = new QQFriend("Cream cheese mushroom soup", "1706046690",new QQFriend("First sight","1415478419")); QQFriend clone = (QQFriend)qqFriend.clone(); // Running result: false System.out.println(qqFriend.getQqFriend() == clone.getQqFriend()); } }
When shallow copy copies a new object through the clone() method, the friend attribute of the object will also be copied into a new attribute. At this time, we finished the deep copy.
-
Deep copy (serialization)
We can also complete the deep copy by serialization. We implement the serialization interface in the QQFriend class.@AllArgsConstructor @Data public class QQFriend implements Serializable { /** * nickname */ private String nickname; /** * QQ number */ private String QQNo; /** * QQ Friends */ private QQFriend qqFriend; public QQFriend(String nickname, String QQNo) { this.nickname = nickname; this.QQNo = QQNo; } public Object cloneBySerializable() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); QQFriend qqFriend = (QQFriend) ois.readObject(); bos.close(); oos.close(); bis.close(); ois.close(); return qqFriend; } }
Operation results
public class PrototypeTest { public static void main(String[] args) throws Exception { QQFriend qqFriend = new QQFriend("Cream cheese mushroom soup", "1706046690",new QQFriend("First sight","1415478419")); QQFriend clone = (QQFriend)qqFriend.cloneBySerializable(); // Running result: false System.out.println(qqFriend.getQqFriend() == clone.getQqFriend()); } }
5, Source code analysis
In Spring, when configuring bean s, the prototype value of the scope attribute is the prototype pattern used.
We go directly to the doGetBean() method of the AbstractBeanFactory class.
After entering the doGetBean() method, you can find that spring judges the parameters and calls createBean to create the object of prototype pattern
6, Analysis of advantages and disadvantages
advantage:
- Using prototype pattern reuse to create instance objects is better than using constructor to recreate objects.
- The prototype pattern can simplify the creation process and directly modify the value of existing object instances to achieve the purpose of reuse.
Disadvantages:
- The cloneable identifier is provided in Java. The Object can be copied, but the clone method of the Object must be overwritten before it can be copied.
7, Applicable scenario
When the constructor defined in the class is complex or many instance objects are created circularly in memory, the prototype pattern can be used to reuse unused objects for creating new objects.
8, Summary
In fact, prototype mode is simply cloning, which is used to create duplicate objects while ensuring performance. This type of design pattern is a creation pattern, which provides the best way to create objects. This pattern implements a prototype interface that is used to create a clone of the current object.