Design pattern learning 05 (Java implementation) – prototype pattern

Time:2021-7-5

Write on the front

  • Take notes on learning design patterns
  • Improve the flexible use of design patterns

Learning address

https://www.bilibili.com/vide…

https://www.bilibili.com/vide…

Reference article

http://c.biancheng.net/view/1…

Project source code
https://gitee.com/zhuang-kang/DesignPattern

6. Prototype mode

6.1 definition and characteristics of prototype model

The definition of prototype pattern is as follows:Using an instance that has been created as a prototype, a new object that is the same or similar to the prototype is created by copying the prototype object. Here, the prototype instance specifies the kind of object to be created.Creating objects in this way is very efficient. You don’t need to know the details of object creation at all. For example, the installation of Windows operating system is usually time-consuming, and if it is copied, it will be much faster.

The advantages of prototype mode are as follows

  • The prototype mode of Java is based on the replication of memory binary stream, which is better than the direct new object in performance.
  • Deep cloning can be used to save the state of an object, and prototype mode can be used to copy an object and save its state, which simplifies the process of creating an object, so that it can be used when necessary (for example, to restore to a certain state in History), and can assist in the implementation of undo operation.

The disadvantages of prototype mode are as follows

  • You need to configure a clone method for each class
  • The clone method is located inside the class. When modifying the existing class, you need to modify the code, which violates the open close principle.
  • When implementing deep cloning, we need to write more complex code, and when there are multiple nested references between objects, in order to achieve deep cloning, the class corresponding to each layer of objects must support deep cloning, which will be more troublesome. Therefore, deep cloning and shallow cloning should be used properly.

6.2 structure and implementation of prototype pattern

6.2.1 structure of prototype model

The prototype pattern includes the following main roles.

  1. Abstract prototype class: Specifies the interfaces that a concrete prototype object must implement.
  2. Concrete prototype class: implements the clone () method of the Abstract prototype class, which is a replicable object.
  3. Access class: use the clone () method in the concrete prototype class to copy new objects.

6.2.2 code implementation

Shallow clone: create a new object with the same attributes as the original object. For non basic type attributes, it still points to the memory address of the object pointed to by the original attribute.

Deep clone: create a new object, and other objects referenced in the attribute will be cloned, no longer pointing to the original object address.

6.2.2.1 light copy

IdCard

package com.zhuang.prototype.shallowclone;

/**
 * @Classname IdCard
 *Example of @ description shallow copy
 * @Date 2021/3/19 12:16
 * @Created by dell
 */

public class IdCard {
    private String id;

    public IdCard(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "IdCard{" +
                "id=" + id +
                '}';
    }
}

Person

package com.zhuang.prototype.shallowclone;

/**
 * @Classname Person
 *Example of @ description shallow copy
 * @Date 2021/3/19 12:17
 * @Created by dell
 */

public class Person implements Cloneable {

    private String name;
    private int age;
    private IdCard idCard;

    public Person() {
    }

    public Person(String name, int age, IdCard idCard) {
        this.name = name;
        this.age = age;
        this.idCard = idCard;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

PersonTest

package com.zhuang.prototype.shallowclone;

/**
 * @Classname PersonTest
 *@ description shallow copy test class
 * @Date 2021/3/19 12:17
 * @Created by dell
 */

public class PersonTest {
    public static void main(String[] args) throws Exception {
        Person person = new person ("Zhang San", 20, new IDcard ("10086");

        Person person1 = (Person) person.clone();
        Person person2 = (Person) person.clone();

        System.out.println(person);
        System.out.println(person1);
        System.out.println(person2);

    }
}

Design pattern learning 05 (Java implementation) - prototype pattern

We found that it can be achieved byimplements CloneableTo complete the shallow copy, the basic variable is the value transfer clone, and the reference objectIdCardIt’s reference passing, which is not in line with our object-oriented thinkingPersonThere should be an independent oneIdCardInstead of sharing one, and to solve this problem, we need to use deep cloning

6.2.2.2 deep copy (type 1)

IdCard

package com.zhuang.prototype.deepclone.one;

/**
 * @Classname IdCard
 *An example of @ description deep cloning
 * @Date 2021/3/19 12:33
 * @Created by dell
 */
//Implementation of Cloneable interface
public class IdCard implements Cloneable {
    private String id;

    public IdCard(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "IdCard{" +
                "id='" + id + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Person

package com.zhuang.prototype.deepclone.one;

/**
 * @Classname Person
 *An example of @ description deep cloning
 * @Date 2021/3/19 12:33
 * @Created by dell
 */

public class Person implements Cloneable {
    private String name;
    private int age;
    private IdCard idCard;

    public Person(String name, int age, IdCard idCard) {
        this.name = name;
        this.age = age;
        this.idCard = idCard;
    }

    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "Person{" +
                "personHashCode=" + this.hashCode() +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", idCard=" + idCard +
                ", idCardHashCode=" + idCard.hashCode() +
                '}';
    }

    //Deep cloning needs to be implemented manually, and clone method should also be implemented in object reference
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //Complete the copy of basic data type
        //The object created with the new keyword is a reference type

        Object person = super.clone();

        //Handle reference types separately
        Person p = (Person) person;
        IdCard idCard = (IdCard) p.getIdCard().clone(); // Realize your own cloning
        p.setIdCard(idCard);
        return p;
    }
}

PersonTest

package com.zhuang.prototype.deepclone.one;

import java.io.Serializable;

/**
 * @Classname PersonTest
 *@ description deep clone test class
 * @Date 2021/3/19 12:33
 * @Created by dell
 */

public class PersonTest implements Serializable {
    public static void main(String[] args) throws Exception {

        Person person = new person ("Zhang San", 20, new IDcard ("10086");

        Person person1 = (Person) person.clone();
        Person person2 = (Person) person.clone();

        System.out.println(person);
        System.out.println(person1);
        System.out.println(person2);

    }
}

Design pattern learning 05 (Java implementation) - prototype pattern

This deep cloning method perfectly solves the problem that when the data type is a reference type, only the address of the original reference object is copied instead of the reference of a new reference object. However, there is a big drawback in this implementation. You need to implement the clone method in every object. If you write all the classes yourself, there is no problem. Just implement it, But it’s a bit of a problem. However, if you refer to a third-party class, you can’t modify the source code. In this way, it’s obviously impossible to achieve deep cloning

6.2.2.2 deep copy (second)

IdCard

package com.zhuang.prototype.deepclone.two;

/**
 * @Classname IdCard
 *Example 2 of @ description deep cloning
 * @Date 2021/3/19 12:33
 * @Created by dell
 */
//Implement serializable interface
public class IdCard implements Serializable {
    private String id;

    public IdCard(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "IdCard{" +
                "id='" + id + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Person

package com.zhuang.prototype.deepclone.two;

import java.io.*;

/**
 * @Classname Person
 *Example 2 of @ description deep cloning
 * @Date 2021/3/19 12:33
 * @Created by dell
 */

public class Person implements Serializable {
    private String name;
    private int age;
    private IdCard idCard;

    public Person(String name, int age, IdCard idCard) {
        this.name = name;
        this.age = age;
        this.idCard = idCard;
    }

    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "Person{" +
                "personHashCode=" + this.hashCode() +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", idCard=" + idCard +
                ", idCardHashCode=" + idCard.hashCode() +
                '}';
    }

    //How to serialize
    public Person deelClone() {
        //Create a stream object
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            //Serialization
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            //Deserialization
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return (Person) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                ois.close();
                bis.close();
                oos.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

PersonTest

package com.zhuang.prototype.deepclone.two;

/**
 * @Classname PersonTest
 *@ description deep clone test class
 * @Date 2021/3/19 12:33
 * @Created by dell
 */

public class PersonTest {
    public static void main(String[] args) throws Exception {
        //Create an object
        Person person = new person ("Zhang San", 20, new IDcard ("10086");

        //Clone two objects
        Person person1 = (Person) person.deelClone();
        Person person2 = (Person) person.deelClone();
        System. Out. Println ("deep copy (the second way to implement serialization interface)");
        //Print three person information
        System.out.println(person);
        System.out.println(person1);
        System.out.println(person2);

    }
}

Design pattern learning 05 (Java implementation) - prototype pattern

In this way, we need to write the deepclone method manually, and use the serialization and deserialization in Java stream to realize deep cloning. However, in this way, we need to inherit the serializable interface in every class. In this way, if you call a third-party class, it is possible that the serializable interface is not implemented in the third-party class, but generally speaking, Most of them will be implemented. Generally speaking, this kind of comparison is recommended and efficient

6.3 application scenarios of prototype pattern

  • Objects are the same or similar, that is, when only a few individual attributes are different.
  • It costs a lot to create objects, such as long initialization time, too much CPU or too much network resources, which need to be optimized.
  • Creating an object requires tedious data preparation or access rights, and needs to improve performance or security.
  • This kind of object is widely used in the system, and each caller needs to reassign its properties.
  • In spring, prototype pattern is widely used,For example, scope =’prototype ‘, JSON. Parseobject ()And so on are the concrete application of prototype pattern.

6.4 precautions and details of prototype mode

  • When creating a new object is more complex, we can use the prototype pattern to simplify the process of creating the object and improve the efficiency at the same time
  • It does not need to reinitialize the object to get the running state of the object dynamically
  • If the original object changes (adding or reducing attributes), other cloned objects will also change accordingly without modifying the code

Write at the end

  • If my article is useful to you, please give me some, thank you!
  • If you have any questions, please point them out in the comments area!