Start with a picture, and the rest is all up to writing...

Design pattern article collection: http://aphysia.cn/categories/designpattern

111

Preface

Students who have been in contact with Spring or Springboot Bean is singleton by default, that is, the same object is shared globally, and different objects will not be used because of different requests. We will not discuss singletons here. We have already discussed singletons. The benefits of the example pattern and various implementations, if you are interested, you can learn about it: http://aphysia.cn/archives/designpattern1. In addition to singletons, Spring can also set other scopes, that is, scope="prototype" . This is the prototype mode. Every time a request comes, a new object is created. This object is created according to the prototype instance.

Definition of prototype pattern

The prototype mode, which is also a kind of creation mode, refers to the use of prototype instances to specify the types of objects to be created, and to create new objects by copying these prototypes. In short, it is copy. Generally applicable to:

  • The instance is more complicated, the cost of complete creation is high, and the direct copy is relatively simple
  • The constructor is more complicated, and the creation may produce a lot of unnecessary objects

    advantage:

  • Hidden the specific details of creating an instance
  • Create objects are more efficient
  • If an object has a large number of the same properties and only a small number of them need specialization, you can directly use the object copied in the prototype mode and modify it to achieve the goal.

How the prototype mode is implemented

Generally speaking, the prototype mode is used to copy objects, so the copied object must have a prototype class, that is, Prototype , Prototype need to implement the Cloneable interface, to achieve this interface to be copied, and then rewrite the clone() method, according to different types To quickly get the prototype object.

We first define a prototype class Fruit :

public abstract class Fruit implements Cloneable{
    String name;
    float price;

    public String getName() {
        return name;
    }

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

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

And the entity class Apple , Pear , Watermelon extends the Fruit class:

public class Apple extends Fruit{
    public Apple(float price){
        name = "苹果";
        this.price = price;
    }
}
public class Pear extends Fruit{
    public Pear(float price){
        name = "雪梨";
        this.price = price;
    }
}
public class Watermelon extends Fruit{
    public Watermelon(float price){
        name = "西瓜";
        this.price = price;
    }
}

Create a cache class to get different fruit types. Each time you get it, take it out according to different types, copy it once and return:

public class FruitCache {
    private static ConcurrentHashMap<String,Fruit> fruitMap =
            new ConcurrentHashMap<String,Fruit>();
    static {
        Apple apple = new Apple(10);
        fruitMap.put(apple.getName(),apple);

        Pear pear = new Pear(8);
        fruitMap.put(pear.getName(),pear);

        Watermelon watermelon = new Watermelon(5);
        fruitMap.put(watermelon.getName(),watermelon);
    }

    public static Fruit getFruit(String name){
        Fruit fruit = fruitMap.get(name);
        return (Fruit)fruit.clone();
    }
}

Test, get different fruits separately, and compare the same type obtained twice, you can find that the same type obtained twice is not the same object:

public class Test {
    public static void main(String[] args) {
        Fruit apple = FruitCache.getFruit("苹果");
        System.out.println(apple);

        Fruit pear = FruitCache.getFruit("雪梨");
        System.out.println(pear);

        Fruit watermelon = FruitCache.getFruit("西瓜");
        System.out.println(watermelon);

        Fruit apple1 = FruitCache.getFruit("苹果");
        System.out.println("是否为同一个对象" + apple.equals(apple1));
    }
}

The results are as follows:


Fruit{name='苹果', price=10.0}
Fruit{name='雪梨', price=8.0}
Fruit{name='西瓜', price=5.0}
false

Test it again, let's see if the name attribute inside is the same object:

public class Test {
    public static void main(String[] args) {
        Fruit apple = FruitCache.getFruit("苹果");
        System.out.println(apple);

        Fruit apple1 = FruitCache.getFruit("苹果");
        System.out.println(apple1);
        System.out.println("是否为同一个对象:" + apple.equals(apple1));
        System.out.println("是否为同一个字符串对象:" + apple.name.equals(apple1.name));
    }
}

The result is as follows, the string inside is indeed the same object:

Fruit{name='苹果', price=10.0}
Fruit{name='苹果', price=10.0}
是否为同一个对象:false
是否为同一个字符串对象:true

Why is this? because the clone() used above is a shallow copy! ! ! However, there is one thing that the string is immutable in Java. If it is modified, the original string will not be modified. Due to the existence of this attribute, it is similar to a deep copy of . If the attribute is another custom object, then you have to pay attention, shallow copy will not really copy the object, only a reference.

Here I have to introduce the difference between shallow copy and deep copy:

  • Shallow copy: There is no real copy of the data, just a pointer to the memory address of the data is copied
  • Deep copy: not only creates a new pointer, but also copies a copy of data memory

If we use Fruit apple = apple1 , it just copies the reference of the object. In fact, it is still the same object. Although the object is different in the above situation, Apple attribute still belongs to the same reference, the address is still the same, and they share the original The attribute object name .

How to make a deep copy? generally has the following solutions:

  • Directly the new object, this does not need to be considered
  • Serialization and deserialization: After serializing first, and then deserializing back, you can get a new object. Note that the Serializable interface must be implemented.
  • clone() method to rewrite the object yourself

Serialization to achieve deep copy

The serialization implementation code is as follows:

Create a Student class and School categories:

import java.io.Serializable;

public class Student implements Serializable {
    String name;

    School school;

    public Student(String name, School school) {
        this.name = name;
        this.school = school;
    }
}
import java.io.Serializable;

public class School implements Serializable {
    String name;

    public School(String name) {
        this.name = name;
    }
}

Serialized copy class:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class CloneUtil {
    public static <T extends Serializable> T clone(T obj) {
        T result = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(obj);
            objectOutputStream.close();

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            // 返回生成的新对象
            result = (T) objectInputStream.readObject();
            objectInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

Test category:


public class Test {
    public static void main(String[] args) {
        School school = new School("东方小学");
        Student student =new Student("小明",school);

        Student student1= CloneUtil.clone(student);
        System.out.println(student.equals(student1));
        System.out.println(student.school.equals(student1.school));
    }
}

The above results are all false , indicating that it is indeed not the same object, and a deep copy has occurred.

clone realizes deep copy

The previous Student and School both implement the Cloneable interface, and then rewrite the clone() method:


public class Student implements Cloneable {
    String name;

    School school;

    public Student(String name, School school) {
        this.name = name;
        this.school = school;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.school = (School) school.clone();
        return student;
    }
}

public class School implements Cloneable {
    String name;

    public School(String name) {
        this.name = name;
    }

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

Test category:

public class Test {
    public static void main(String[] args) throws Exception{
        School school = new School("东方小学");
        Student student =new Student("小明",school);

        Student student1= (Student) student.clone();
        System.out.println(student.equals(student1));
        System.out.println(student.school.equals(student1.school));
    }
}

The test results are the same, the same is false , and a deep copy has also occurred.

Summarize

The prototype mode is suitable for scenarios where many steps or resources are required to create an object. Between different objects, only some of the properties need to be customized, and the others are the same. Generally speaking, the prototype mode does not exist alone, but will be different from others. Used together with the mode. It is worth noting that copy is divided into shallow copy and deep copy. If data modification occurs in shallow copy, the data of different objects will be modified because they share metadata.

[Profile of the author] :
Qin Huai, [161b40d3f4a20c Qinhuai Grocery Store ], the road to technology is not at a time, the mountains are high and the rivers are long, even if it is slow, it will never stop. Personal Writing direction: the Java source code parsing, JDBC , Mybatis , Spring , redis , distributed, wins the Offer, LeetCode etc., carefully write each article, do not like the title of the party, do not like bells and whistles, mostly to write a series of articles , I cannot guarantee that what I have written is completely correct, but I guarantee that what I have written has been practiced or searched for information. I hope to correct any omissions or errors.

refers to all offer solutions PDF

What did I write in 2020?

Open source programming notes

attention to the public account "Qin Huai Grocery Store" and you can receive the PDF Offer V1 version. The V2 version has added questions. It is still in the update of humming, and the solution for each problem is added C++ , so stay tuned .


秦怀杂货店
147 声望38 粉丝

山高水长,纵使缓慢,驰而不息。