Statement: For reprint, please attach the link to the original text

Tip: the title sequence starts at 3, reflecting the order in which the various design pattern notes are published. For example, in the first article, factory Pattern, a common Java design pattern for beginners, starts at 2.

Understanding is added after the title because the factory pattern uses the prototype pattern less than the singleton pattern, but deep and shallow copies of the prototype pattern are something to know!

3. Prototype patterns (Understanding)

3.1 Introduction to prototype mode

  • Prototype design pattern

    • Object creation mode is an object creation mode that uses prototype instances to specify the type of objects to be created, and creates new objects by copying these prototypes. It is mainly used to create duplicate objects while ensuring performance
    • It works by passing a prototype object to the creation object, which implements the creation process by asking the prototype object to copy itself
    • The simplest design pattern is to implement an interface, override a method and complete the prototype pattern
  • The core of

    • Prototype: interface that declares clone methods. Cloneable interface is the common parent of all concrete Prototype classes
    • ConcretePrototype: ConcretePrototype class
    • Client: Lets a prototype object clone itself to create a new object
  • Application scenarios

    • New objects are expensive to create and can be obtained by copying existing objects in the prototype pattern
    • If the system wants to save the state of the object, use it as a backup

3.2 Prototype pattern cases

Let’s start by creating a concrete prototype class person.java that implements the Cloneable interface, overriding the clone() method:

/ * * *@Auther: csp1999
 * @Date: 2020/11/08 / coasts *@DescriptionThe Person concrete prototype class implements the Cloneable interface and can be cloned */
public class Person implements Cloneable{

    private String name;
    private int age;

    public Person(a){
        System.out.println("Empty parameter constructor call...");
    }

    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;
    }

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

    /** * override the clone method to return the Person object type **@return
     * @throws CloneNotSupportedException
     */
    @Override
    public Person clone(a) throws CloneNotSupportedException {
        return (Person) super.clone(); }}Copy the code

Call and print the results in the test class:

@Test
public void testPropotype(a) throws CloneNotSupportedException {
    Person person1 = new Person();
    person1.setAge(22);
    person1.setName("csp");
    System.out.println(person1);
    Person person2 = person1.clone();
    person2.setName("hzw");
    System.out.println(person2);
}
Copy the code

The results are as follows:

Empty parameter constructor call... Person{name='csp', age=22}
Person{name='hzw', age=22}
Copy the code

As you can see from the result, person2 is copied from person1 and the data content is the same. Note, however, that person1 calls clone(); Method to get person2 without passing through the null parameter constructor in the Person class, so it prints out only one null parameter constructor call… .

Next, we add the new complex data type member variables to Person: List

private List<String> list;
Copy the code

Let’s test again:

@Test
public void testPropotype(a) throws CloneNotSupportedException {
    Person person1 = new Person();
    person1.setAge(22);
    person1.setName("csp");
    // Initialize the list and add data to it
    person1.setList(new ArrayList<>());
    person1.getList().add("aaa");
    person1.getList().add("bbb");
    System.out.println("person1:"+person1);
    Person person2 = person1.clone();
    person2.setName("hzw");
    // Add a data item to the list in peron2
    person2.getList().add("ccc");
    System.out.println("person2"+person2);
    System.out.println("person1:"+person1);
    boolean flag1 = person1 == person2;
    System.out.println("Is the reference address for person1 and person2 the same:" +  flag1);
    boolean flag2 = person1.getList() == person2.getList();
    System.out.println("Is the list reference address for person1 and person2 the same:" +  flag2);
}
Copy the code

Output result:

Empty parameter constructor call... person1:Person{name='csp', age=22, list=[aaa, bbb]}
person2Person{name='hzw', age=22, list=[aaa, bbb, ccc]}
person1:Person{name='csp', age=22, list=[aaa, BBB, CCC]} person1 and person2 reference address is the same:falseIs the list reference address for person1 and person2 the same:true
Copy the code

As can be seen from the results:

  • When the clone is completed, it essentially creates a new Person object and assigns it a new storage address and reference, so the address reference for person1 and person2 are different.
  • And forPersonObject’s complex type member variable list, when cloned, is actually copied from the objectperson1Copy the referenced address of list toperson2List, not newnewCreate a List;
  • So they’re actually sharing a list of references to the same address, soperson1.getList() == person2.getList();trueWhich explains whyperson2Add data to the list ofcccWhen,person1The list in is also addedcccAnd this situation is calledShallow copy;

So how to solve the shallow copy problem? Read on!

3.1 Prototype Mode Deep copy/Shallow copy

  • Remaining issues:

    • New objects are constructed by instantiating a class. In contrast, the stereotype pattern generates new objects by copying an existing object

    • Shallow copy implements Cloneable, and deep copy reads binary streams by implementing Serializable

    • expand

      • Shallow copy:

        If the member variables of the prototype object are primitive data types (int, double, byte, Boolean, char, etc.), a copy will be made to the clone. If the member variables of the prototype Object are of reference type, then the address of the reference Object is copied to the clone. That is, the clone and the member variables of the prototype Object point to the same memory address by overriding the clone() method of the Object classCopy the code
      • Deep copy:

        A copy of the prototype object's member variables is made to the clone regardless of whether they are primitive data types or reference types. If you need to implement deep cloning, you can do so through methods such as SerializableCopy the code
  • advantages

    • When creating a new object instance is complicated, using the prototype pattern can simplify the object creation process and improve the efficiency of new instance creation
    • It can assist in the implementation of undo operations, using deep cloning to save the state of the object, using prototype mode to copy the object and save its state, so that it can be used to restore to the historical state when needed
  • disadvantages

    • Each class needs to be equipped with a clone method. When modifying existing classes, the source code needs to be modified, which violates the “open and closed principle”.
    • The implementation of deep cloning requires complex code, and when there are multiple nested references between objects, the corresponding classes of each layer of objects must support deep cloning

Deep copy implementation:

First, the Person object implements the Serializable interface, and then custom deepClone() :

/** * deep copy ** Note: to implement serialization interface *@return* /
public Person deepClone(a) {
    try {
        // Output (serialization)
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this);
        // Input (deserialize)
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Person person = (Person) ois.readObject();
        return person;
    } catch (Exception e) {
        e.printStackTrace();
        return null; }}Copy the code

Verify that the deep copy is successful:

@Test
public void testPropotype(a) throws CloneNotSupportedException {
    Person person1 = new Person();
    person1.setAge(22);
    person1.setName("csp");
    // Initialize the list and add data to it
    person1.setList(new ArrayList<>());
    person1.getList().add("aaa");
    person1.getList().add("bbb");
    System.out.println("person1:"+person1);
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- shallow copy -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
    //Person person2 = person1.clone();
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- deep copy -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
    Person person2 = person1.deepClone();
    person2.setName("hzw");
    // Add a data item to the list in peron2
    person2.getList().add("ccc");
    System.out.println("person2"+person2);
    System.out.println("person1:"+person1);
    boolean flag1 = person1 == person2;
    System.out.println("Is the reference address for person1 and person2 the same:" +  flag1);
    boolean flag2 = person1.getList() == person2.getList();
    System.out.println("Is the list reference address for person1 and person2 the same:" +  flag2);
}
Copy the code

Output result:

Empty parameter constructor call... person1:Person{name='csp', age=22, list=[aaa, bbb]}
person2Person{name='hzw', age=22, list=[aaa, bbb, ccc]}
person1:Person{name='csp', age=22, list=[aaa, BBB]} person1 and person2 reference address is the same:falseIs the list reference address for person1 and person2 the same:false
Copy the code

Person2 (list); person1 (list); person2 (list);

Later I will update other design mode blog posts, if the article is helpful to you, hope to click on the likes/favorites/follow! O ~ O (studying studying)