“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Prototype Patter is a creation pattern that provides the best way to create duplicate objects. The definition is: “Specify what kind of objects to create with prototype instances, and create new objects by copying these prototypes.”

1. Mode introduction

Prototype Patter is a creation pattern that provides the best way to create duplicate objects. The definition is: “Specify what kind of objects to create with prototype instances, and create new objects by copying these prototypes. “

2. Application scenarios

The prototype pattern primarily addresses the problem of how best to create a repeating object.

It is worth noting that using the prototype pattern assumes that the cost of creating an object is high and that there is not much difference between the old and new objects, otherwise it complicates a simple problem. For example, when objects need to be fetched from complex IO, the performance created using the prototype pattern is better than the performance fetched from IO.

3. Implementation method

In Java, we can implement copy-based object creation with Object#clone(). Here is a simple example.

/ / user classes
public class User {
    private String name;
    private int age;
    private Address address;

    public User(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address; }}/ / address class
public class Address {
    private String addressName;

    public Address(String addressName) {
        this.addressName = addressName; }}Copy the code

First create two classes, User and Address, and clone them using Object#clone() in the main method.

public static void main(String[] args) throws CloneNotSupportedException {
    Address address = new Address("Hangzhou");
    User user = new User("East".18, address);
	  System.out.println(user);
    User cloneUser = (User) user.clone();
    System.out.println(cloneUser);
}
Copy the code

The running results are as follows:

io.walkers.planes.pandora.design.patterns.prototype.User@6e0be858
Exception in thread "main" java.lang.CloneNotSupportedException: io.walkers.planes.pandora.design.patterns.prototype.User
	at java.lang.Object.clone(Native Method)
	at io.walkers.planes.pandora.design.patterns.prototype.User.main(User.java:31)
Copy the code

What happened? How could it be wrong? Clone (Object#clone()) in Java. To find out why, take a look at the comments in the Object#clone() source code.

Throws: CloneNotSupportedException -if the object's class does not support the Cloneable interface. Subclasses that override the clone method can also throw this exception to indicate that an instance cannot be cloned.
Copy the code

Object# clone () method will throw CloneNotSupportedException abnormalities, illustrates the exception is thrown in the comments: When the class does not implement the Cloneable interface, call Object# clone () method will throw CloneNotSupportedException anomalies. This is what the JDK says about the clone method, so we need to ensure that the Cloneable interface is implemented before using Object#clone().

Cloneable: Cloneable: Cloneable: Cloneable: Cloneable: Cloneable: Cloneable: Cloneable: Cloneable

io.walkers.planes.pandora.design.patterns.prototype.User@6e0be858
io.walkers.planes.pandora.design.patterns.prototype.User@61bbe9ba
Copy the code

In the output, the addresses of the two User objects are different, indicating that the cloning is successful.

The User class contains an Address object. The Address object is clone, and the Address object is clone. To verify this, we need to rewrite the toString method of the User class.

@Override
public String toString(a) {
  return "User{" + "name='" + name + '\' ' + ", age=" + age + ", address=" + address + '} ';
}
Copy the code

Then run the main method again and get the following output:

User{name='east', age=18, address=io.walkers.planes.pandora.design.patterns.prototype.Address@6e0be858}
User{name='east', age=18, address=io.walkers.planes.pandora.design.patterns.prototype.Address@6e0be858}
Copy the code

As you can see, the Address object has the same Address value, which means that when cloning is done, the reference type object contained in the class is not cloned by default, but only a copy of its reference Address.

So what if there is a requirement to get a copy of a completely new duplicate object? This actually involves two implementations of the prototype pattern — shallow copy and deep copy.

4. Shallow and deep copies

When copying data, it only copies the basic type data and the address of the reference type object, but does not copy the form of the reference type object itself recursively. This is called shallow copy.

Accordingly, in addition to copying basic type data, the reference type object itself (including other reference type objects contained in the reference type object) is copied. That is, the copied object is completely new, which is called deep copy.

For example, in the prototype pattern demo example described above, this is a shallow copy example (Address objects have the same Address). If I wanted to change it to deep-copy form, I would need to override the clone method of the User class, as follows:

public class User implements Cloneable {
  	// omit other methods and attributes
  
		@Override
    protected Object clone(a) throws CloneNotSupportedException {
        this.address = (Address) address.clone();
        return super.clone(); }}Copy the code

It is important to note that the Address class also implements the Cloneable interface. If the Address class contains objects of other reference types, the clone method of the Address class should also be overridden.

After the transformation is complete, the output is as follows:

User{name='east', age=18, address=io.walkers.planes.pandora.design.patterns.prototype.Address@6e0be858}
User{name='east', age=18, address=io.walkers.planes.pandora.design.patterns.prototype.Address@61bbe9ba}
Copy the code

The Address object in the two User objects has different addresses, indicating that this is a deep copy.

Of course, there is another deep-copy approach: serialize the object and then deserialize it to a new object. But this method is relatively time-consuming.

When to use shallow copy and when to use deep copy: To ensure that the modified new object does not affect the original object, you are advised to use the deep copy. However, if the data volume is very large, shallow copy is recommended to avoid performance impact.

Finally, this article is included in the Personal Speaker Knowledge Base: Back-end technology as I understand it, welcome to visit.