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