一、定义

(1)原型模式是指:原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(有一个模板类的对象,通过拷贝这个对象获取一个一样的对象)。

(2)调用者不需要知道创建对象的细节,不需要调用构造函数。

(3)属于创建型模式。

二、场景

(1)类初始化过程中消耗资源多。

(2)new产生的对象需要一个非常繁琐的过程(数据准备,访问权限)。

(3)构造函数比较复杂。

(4)在一个循环中生产大量对象时。

比如下面这个场景(需要多次的get,set):

这种场景我们可以怎么优化处理呢?

(1)BeanUtils.copy();//原型模式

(2)JSON.parseObject();//通用的方法,直接把值转成对象

(3)Guava   Copy 工具类//原型工具类

原型模式给我们带来的最大的方便就是简化产生对象的这个过程,不需要去通过构造函数构造

三、浅克隆与深克隆

Java中提供了一种类克隆的机制,在java的jdk中就可以实现一种原型模式:

(1)浅克隆

package com.songyan.prototype;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public interface ProtoType {
    ProtoType clone();
}
package com.songyan.prototype;

import java.util.List;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public class ConcretePrototypeA implements ProtoType{
    private int age;
    private String name;
    private List hobbies;

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public List getHobbies() {
        return hobbies;
    }

    public void setHobbies(List hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public ProtoType clone() {
        ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
        concretePrototypeA.setAge(this.age);
        concretePrototypeA.setName(this.name);
        concretePrototypeA.setHobbies(this.hobbies);
        return concretePrototypeA;
    }
}
package com.songyan.prototype;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public class Client {
    public ProtoType startClone(ProtoType concretePrototype){
        ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
        return concretePrototype.clone();
    }
}
package com.songyan.prototype;

import java.util.ArrayList;
import java.util.List;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public class PrototypeTest {
    public static void main(String[] args) {
        ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
        concretePrototypeA.setAge(18);
        concretePrototypeA.setName("songyan");
        List hobbies = new ArrayList<Object>();
        concretePrototypeA.setHobbies(hobbies);

        Client  client = new Client();
        ConcretePrototypeA copy = (ConcretePrototypeA)client.startClone(concretePrototypeA);
        System.out.println(concretePrototypeA);
        System.out.println(copy);
        System.out.println(copy.getHobbies() == concretePrototypeA.getHobbies());
    }

}

这里会发现克隆出来的引用类型的对象,只是复制了原来的引用,指向了同一个对象,这样就会导致一个对象的值改变了,其他的克隆出来的对象的引用的值也会发生改变,这种克隆属于浅克隆。

(2)深克隆

在上面代码的基础上添加深克隆的代码:

package com.songyan.prototype;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public interface ProtoType {
    ProtoType clone();
    ProtoType deepClone();

}
package com.songyan.prototype;

import java.io.*;
import java.util.List;

/**
 * author:songyan
 * date: 2019/10/10
 **/
public class ConcretePrototypeA implements ProtoType,Serializable{

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public List getHobbies() {
        return hobbies;
    }

    public void setHobbies(List hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public ProtoType clone() {
        ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA();
        concretePrototypeA.setAge(this.age);
        concretePrototypeA.setName(this.name);
        concretePrototypeA.setHobbies(this.hobbies);
        return concretePrototypeA;
    }

    /**
     * 对象字节码的直接扩容
     * @return
     */
    @Override
    public ProtoType deepClone() {
        try {
            //在内存中操作
            //将字节码写入内存
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(bos);
            obs.writeObject(this);

            //读取字节码,将字节码转成对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ConcretePrototypeA copy = (ConcretePrototypeA)ois.readObject();
            return copy;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

深克隆是直接克隆对象的字节码生成新的对象。

四、可能出现的问题

(1)问题:单例被破坏

(2)解决:

  1)在clone方法中直接返回单例的对象

  2)不实现cloneable接口

  3)新增readResolve方法

01-26 00:01
查看更多