“This is the 13th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”

1. Overview of prototype pattern

Introduction to prototype patterns

1, Prototype pattern (Prototype pattern) refers to: use an already created instance as a Prototype, by copying the Prototype object to create a new object that is the same or similar to the Prototype. Here, the prototype instance specifies the kind of object to be created.

2. Prototyping is a creative design pattern that allows one object to create another customizable object without knowing the details of how to create it, so it is very efficient to create objects this way.

Clone (); clone(); clone(); clone();

4. Understanding of images: Sun Rasheng pulls out monkey’s hair and makes other Sun Rasheng

Pros and cons of prototyping

Advantages of the prototype pattern:

  • Java’s native prototype pattern is based on copying an in-memory binary stream, which provides better performance than simply new an object.
  • You can use the deep clone mode to save the state of an object. You can use the prototype mode to make a copy of an object and save its state, simplifying the process of creating an object, so that it can be used when needed (such as restoring to a historical state) to assist in the undo operation.

Disadvantages of the prototype pattern:

  • You need to configure a Clone method for each class
  • The Clone method is located inside the class. When modifying an existing class, the code needs to be modified, which violates the open and closed principle.
  • When implementing deep cloning, complex code needs to be written, and when there are multiple nested references between objects, in order to implement deep cloning, the corresponding classes of each layer of objects must support deep cloning, which can be quite troublesome to implement. Therefore, deep cloning, shallow cloning needs to be used properly.

2. Structure diagram of prototype pattern

The structure of the prototype pattern

The archetypal pattern contains the following primary roles.

  1. Prototype: Declares an interface that clones itself.
  2. Concrete prototype class Realizetype: The clone() method of the prototype class is implemented to realize the operation of cloning itself. It is an object that can be copied, and there can be more than one.
  3. Access class PrototypeTes: Copies new objects using the clone() method of the concrete prototype class.

Structure diagram of the prototype pattern

3. Realization of prototype pattern

3.1 Shallow copy and deep copy

Introduction to Shallow copy

For member variables whose data type is a primitive data type, the shallow copy directly passes the value, that is, copies the property value to the new 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. Because the member variable of both objects actually 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.

Shallow copies are implemented using the default clone() method.

Introduction to Deep Copy

The deep copy copies the values of all the basic data types of the object.

Deep copy allocates storage space for all reference datatype member variables and copies the object referenced by each reference datatype member variable until the object is reachable to all objects. That is, to make a deep copy of an object, the entire object is copied.

Deep copy implementation method 1: Rewrite clone method to realize deep copy.

Deep copy implementation method 2: Implement deep copy through object serialization. (Recommended)

3.2 implement shallow copy

The Object class in Java provides the clone() method for shallow copies of objects. Concrete prototype classes can implement shallow copies of objects as long as they implement the Cloneable interface, in this case the Cloneable interface.

Concrete prototype classes:

package com.cheng.prototype;

public class Sheep implements Cloneable{

    private String name;
    private int age;
    private String color;


    public Sheep(a) {}public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor(a) {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString(a) {
        return "sheep{" +
                "name='" + name + '\' ' +
                ", age=" + age +
                ", color='" + color + '\' ' +
                '} ';
    }

    // Override the clone method
    @Override
    protected Object clone(a) {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        returnsheep; }}Copy the code

Access class test: Copy the new object using the clone() method in the concrete prototype class

package com.cheng.prototype;

public class PrototypeTes {
    public static void main(String[] args) {
        Sheep sheep1 = new Sheep("wanli".1."White");

        // Prototype mode completes object creationSheep sheep2 = (Sheep) sheep1.clone(); Sheep sheep3 = (Sheep) sheep1.clone(); Sheep sheep4 = (Sheep) sheep1.clone(); Sheep sheep5 = (Sheep) sheep1.clone(); Sheep sheep6 = (Sheep) sheep1.clone(); System.out.println(sheep2); System.out.println(sheep3); System.out.println(sheep4); System.out.println(sheep5); System.out.println(sheep6); }}Copy the code

Run the access class to test:

This procedure has higher efficiency and expansibility!

3.2. Implement deep copy

Create a reference type class:

package com.cheng.prototype.demo02;

import java.io.Serializable;

public class DeepCloneableTarget implements Serializable.Cloneable {

    private static final long serialVersionUID = 1L;

    private String cloneName;
    private String cloneClass;

    public DeepCloneableTarget(String cloneName,String cloneClass){
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }
    
    @Override
    public String toString(a) {
        return "DeepCloneableTarget{" +
                "cloneName='" + cloneName + '\' ' +
                ", cloneClass='" + cloneClass + '\' ' +
                '} ';
    }
    
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone(); }}Copy the code

Create a concrete prototype class:

package com.cheng.prototype.demo02;

import java.io.*;

public class DeepProtoType implements Serializable.Cloneable {

    public String name;
    public DeepCloneableTarget deepCloneableTarget;


    public DeepProtoType(a){}@Override
    public String toString(a) {
        return "DeepProtoType{" +
                "name='" + name + '\' ' +
                ", deepCloneableTarget=" + deepCloneableTarget +
                '} ';
    }

    // Deep copy implementation 1: Rewrite clone method to implement deep copy
    @Override
    protected Object clone(a) {
        Object deep = null;
        DeepProtoType deepProtoType = null;
        // Copy the basic datatype and String attributes of DeepProtoType
        try {
            deep = super.clone();
            // Then copy the attributes of the reference type DeepCloneableTarget
            deepProtoType = (DeepProtoType) deep;
            deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return deepProtoType;
    }

    // Deep copy implementation 2: Implement deep copy through object serialization. (Recommended),
    // In this way, the object is cloned as a whole, unlike in the first way, the reference object is cloned separately
    public DeepProtoType deepClone(a) {

        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);// Serialize the object

            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType deepType = (DeepProtoType) ois.readObject();// Deserialize the object
            return deepType;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally {
            try {
                if(ois ! =null)
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bis ! =null)
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(oos ! =null)
                    oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bos ! =null)
                    bos.close();
            } catch(IOException e) { e.printStackTrace(); }}}}Copy the code

Access class tests:

package com.cheng.prototype.demo02;

public class Client {
    public static void main(String[] args) {
        DeepProtoType t = new DeepProtoType();

        t.name = "Gods";
        t.deepCloneableTarget = new DeepCloneableTarget("Thousands of miles"."Thousands of miles");

        // Test deep copy implementation 1: Rewrite clone method to implement deep copy,
        DeepProtoType clone1 = (DeepProtoType)t.clone();
        System.out.println("Test deep copy implementation 1: Rewrite clone method to implement deep copy");
        // Prints the prototype object and the hashCode that references the object in the prototype object
        System.out.println(t +","+ t.deepCloneableTarget.hashCode());
        // Prints the clone and the hashCode of the reference object in the clone
        System.out.println(clone1 +","+ clone1.deepCloneableTarget.hashCode());

        System.out.println();

        // Test deep copy implementation 2: Implement deep copy through object serialization. (Recommended)
        DeepProtoType deepClone = t.deepClone();
        System.out.println("Test deep copy implementation 2: Implement deep copy through object serialization. (Recommended)");
        // Prints the prototype object and the hashCode that references the object in the prototype object
        System.out.println(t +","+ t.deepCloneableTarget.hashCode());
        // Prints the clone and the hashCode of the reference object in the clone
        System.out.println(deepClone +","+ deepClone.deepCloneableTarget.hashCode()); }}Copy the code

Run the access class to test: