原型模式(Prototype Pattern)

原型模式(Prototype Pattern)

通过拷贝创建新的对象,调用者不用知道创建细节,不调用构造函数,是一种创建型模式,简而言之就是一个克隆一个对象,使用场景

  • 类初始化消耗资源过多
  • 构造函数比较复杂
  • 循环体中产生大量新的对象

对于原型模式有两种写法,一种浅克隆(克隆对象使用的指向的同一个地址)一种深克隆(克隆对象的内容,地址不同),在【深度拷贝带随机指针的链表】 中我曾经提到。

Shallow clone

@Data
@ToString
public class ConcretePrototype implements Cloneable {

    private int age;
    private String name;
    private List<String> hobbies;

    @Override
    protected ConcretePrototype clone()  {
        try {
            return (ConcretePrototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return  null;
        }
    }
}

To test

public class Client {
    public static void main(String[] args) {
        ConcretePrototype concretePrototype=new ConcretePrototype();
        concretePrototype.setAge(18);
        concretePrototype.setName("Glen");
        List<String> hobbies=new ArrayList<String>();
        hobbies.add("Girls");
        hobbies.add("Techniques");
        concretePrototype.setHobbies(hobbies);

        ConcretePrototype concretePrototype1=concretePrototype.clone();
        concretePrototype1.getHobbies().add("man");
        System.out.println(concretePrototype+"initial..");
        System.out.println(concretePrototype1+"cloned..");
        // They are different space of memory
        System.out.println(concretePrototype==concretePrototype1);
        // for primary data type can be pointed to different space of memory but specific type can not be (they remain point to the same space,such List)
        System.out.println(concretePrototype.getHobbies()==concretePrototype1.getHobbies());
    }
}

To explain:

apparently,for instance, They are different spaces,but for specific, They are same space,so according conclusion,we get that it use shallow clone in basis of jdk for specific type,actually jdk just copy value of address of memory, like value of 'int boolean、char、float、double'  are saved in value of address of memory,but some specific types like List, in fact, their  value of address of memory are saved their value of addres,so just copy their value of addres cause same scenario of  value of addres.

 Deep clone

 method of serialization 

@Data
@ToString
public class ConcretePrototype implements Cloneable,Serializable {

    private int age;
    private String name;
    private List<String> hobbies;

    ConcretePrototype deepClone()  {
        ByteOutputStream byteOutputStream=new ByteOutputStream();
        try {
            ObjectOutputStream objectOutput=new ObjectOutputStream(byteOutputStream);
            objectOutput.writeObject(this);
            ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteOutputStream.getBytes());
            ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
            return (ConcretePrototype) objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

To test

public class Client {
    public static void main(String[] args) {
        ConcretePrototype concretePrototype=new ConcretePrototype();
        concretePrototype.setAge(18);
        concretePrototype.setName("Glen");
        List<String> hobbies=new ArrayList<String>();
        hobbies.add("Girls");
        hobbies.add("Techniques");
        concretePrototype.setHobbies(hobbies);
        // We just replace the method of our cloning
        ConcretePrototype concretePrototype1=concretePrototype.deepClone();
        concretePrototype1.getHobbies().add("man");
        System.out.println(concretePrototype+"initial..");
        System.out.println(concretePrototype1+"cloned..");
        System.out.println(concretePrototype==concretePrototype1);
        System.out.println(concretePrototype.getHobbies()==concretePrototype1.getHobbies());
    }
}

 To explain

We use  serialization to create the classess, do you remember that we had mentioned the method in singleton (use serialization  to destroy),so that we can not make a classess to be both singleton and  prototype!! do you remember that if we override 'readResolve' what is the result, Right! The 'java.io.ObjectInputStream#readObject0' will not create the new classess, so we must not override 'readResolve'

Be applied into the souce of code

java.util.ArrayList#clone

 java.util.HashMap#clone

 

 We find out that resouce of code above both Override the 'java.lang.Object#clone' so can we  Override that then add our logical code in it?definitely

    ConcretePrototype deepCloneHobbies() {
        try {
            ConcretePrototype clone = (ConcretePrototype) super.clone();
            clone.hobbies=(List)((ArrayList)clone.getHobbies()).clone();
            return clone;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

 Hi,we solve it perfectly,but if there are many specific type in the same class, do you want to do it more?so, personally, i think we use  method of serialization more complete!

Sum up

advantage

  • Be base on Binary stream to copy more  efficient than  to create a instance
  • To simplify process of creating a class

disadvantage

  we must add a method of clone in each classess in order to with clone to create classess

 

原文地址:https://www.cnblogs.com/UpGx/p/14664144.html