“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
Prototype design pattern
1. Understanding of prototype design pattern
The prototype pattern is a creation pattern that uses existing prototype instances to specify what kind of objects to create, and creates new objects by copying these prototypes. Typically used to create duplicate objects and ensure performance. The prototype mode is mainly realized by cloning, which is mainly divided into shallow clone (shallow copy) and deep clone (deep copy).
2. Clone: shallow copy and deep copy
2.1 shallow copy
- For the primitive data type variable in the copied object, the value is directly passed, that is, the primitive type variable of the copied object is directly copied from the original object.
- For a member variable whose data type is a reference to a data type, such as an array, an object of a class, etc., shallow copy passes by reference, which simply copies the reference value (memory address) of the member variable to the new object. In fact, the member variable of both objects refers to the same instance. In this case, modifying the member variable in one object affects the value of the member variable in the other object
- The clone method on Java objects is a shallow copy by default.
2.2 deep copy
- Copy all the basic datatype variables of the object
- Allocates storage space for all member variables that reference data types, and copies the objects referenced by each member variable of reference data types until the objects are reachable. That is, to make a deep copy of an object, the entire object is copied
- Deep copy can be implemented in two ways
- By overriding the clone() method of the Object
- Serialization through objects (recommended)
3. The uml class diagram
– Schematic diagram description
- Prototype: a Prototype class that declares an interface that clones itself
- ConcretePrototype: ConcretePrototype class that implements an operation that clones itself
- Client: Make a prototype object clone itself to create a new object (with the same properties)
4. The traditional case — copy objects
The following classes omit the get and set methods
public class Sheep { private String name; private int age; private String color; } public static void main(String[] args) {// TODO auto-generated method Sheep = new Sheep(" Tom ", 1, 1) "White"); Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); / /... }Copy the code
Disadvantages: This way, low efficiency, when the need to copy the object is particularly long, the amount of code is relatively large. And for referenced objects, data and other types of data, to achieve deep copy, the code is more complex.
5. Prototype mode — shallow copy
1. Shallow copy. Objects only need to implement Cloneable interface and use the default Object inheritance method
public class Sheep implements Cloneable { private String name; private int age; private String color; Private String address = "private String address "; public Sheep friend; @Override public String toString() { return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]"; @override protected Sheep clone() {Sheep Sheep = null; try { sheep = (Sheep)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return sheep; }}Copy the code
- The test class
Public static void main(String[] args) {Sheep = new Sheep(" Tom ", 1, "white "); Sheep. Friend = new sheep ("jack", 2, "black "); Sheep sheep2 = (Sheep)sheep.clone(); // Clone Sheep sheep3 = (Sheep)sheep.clone(); //sheep2 :Sheep [name= Tom, age=1, color= white, Address = sheep2.friend:1807837413 system.out.println ("sheep2 :" + sheep2 + "sheep2 sheep2.friend.hashCode()); // false sheep3.friend:1807837413 System.out.println((sheep == sheep3) + " sheep3.friend:" + sheep3.friend.hashCode()); }Copy the code
We can see that the two objects are indeed not equal, but their reference type variables refer to the same object instance. This is the shallow copy feature we talked about earlier.
6. Prototype mode — Deep copy
6.1 Deep Copy – Override the Clone method
public class DeepProtoType implements Cloneable{ public String name; If the attribute contains the attribute of the reference type, to implement full deep clone, it also needs to implement the Cloneable interface. Clone method public DeepCloneableTarget DeepCloneableTarget; public DeepProtoType() { super(); } / / deep copy - 1 use the clone method @ Override protected Object clone () throws CloneNotSupportedException {Object deep = null; Deep = super.clone(); DeepProtoType DeepProtoType = (DeepProtoType)deep; deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone(); // TODO Auto-generated method stub return deepProtoType; }}Copy the code
Although this method can achieve the effect of deep copy, it is generally not recommended to use this method when there are too many reference type attributes in the object, or reference type attributes also contain reference types.
6.2 Deep Copy — Serialization (recommended)
public class DeepProtoType implements Serializable{ public String name; //String attribute //DeepCloneableTarget also implements Serializable interface, Otherwise the Java. IO. NotSerializableException public DeepCloneableTarget DeepCloneableTarget; Public prototype () {super(); Public Object deepClone() {ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; Try {// serialize bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); Bis = new ByteArrayInputStream(bos.tobyteArray ()); bis = new ByteArrayInputStream(bos.tobyteArray ()); ois = new ObjectInputStream(bis); DeepProtoType copyObj = (DeepProtoType)ois.readObject(); return copyObj; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; } finally {// Close the stream try {bos.close(); oos.close(); bis.close(); ois.close(); } catch (Exception e2) { // TODO: handle exception System.out.println(e2.getMessage()); }}}}Copy the code
This deep clone requires that both the class and its attribute classes implement the Serializable interface
7. To summarize
-
When creating a new object is complicated, the prototype pattern can be used to simplify the object creation process and improve efficiency
-
Instead of reinitializing the object, the state of the object at run time is dynamically obtained
-
If the original object changes (adding or subtracting attributes), the other clones will change accordingly, without changing the code
-
Complex code may be required to implement procloning
-
Disadvantages: You need to have a clone method for each class, which is not too difficult for a brand new class, but modifying an existing class requires modifying its source code, which violates THE OCP principle.