一、定义
(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方法