定义
- 原型模式(Prototype Pattern)是指原型实例指定创建对象的 种类,并且通过拷贝这些原型创建新的对象。
- 调用者不需要知道任何创建细节,不调用构造函数。
适用场景
- 类初始化消耗资源较多。
- new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
- 构造函数比较复杂
- 循环体中生产大量对象时,可读性下降。
- 原型模式就是快速构建对象的方法总结, 简单工厂将getter、setter封装到某个方法中 JDK提供的实现Cloneable接口,实现快速复制 scope=“prototype”,scope=”singleton”
优点
- 原型模式性能比直接new一个对象性能高
- 简化了创建过程
缺点
- 必须配备克隆(或者可拷贝)方法
- 对克隆复杂对象或对克隆出的对象进行复杂改造时,易带来风险
- 深拷贝、浅拷贝要运用得当
实例
简单克隆
创建原型Prototype接口
public interface Prototype{ Prototype clone(); }
创建具体需要克隆的对象ConCretePrototype
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 ConcretePrototypeA clone() { ConcretePrototypeA concretePrototype = new ConcretePrototypeA(); concretePrototype.setAge(this.age); concretePrototype.setName(this.name); concretePrototype.setHobbies(this.hobbies); return concretePrototype; } }
创建client对象
public class Client { private Prototype prototype; public Client(Prototype prototype){ this.prototype = prototype; } public Prototype startClone(Prototype concretePrototype){ return (Prototype)concretePrototype.clone(); } }
测试实例
// 创建一个具体的需要克隆的对象 ConcretePrototypeA concretePrototype = new ConcretePrototypeA(); // 填充属性,方便测试 concretePrototype.setAge(18); concretePrototype.setName("prototype"); List hobbies = new ArrayList<String>(); concretePrototype.setHobbies(hobbies); System.out.println(concretePrototype); // 创建Client对象,准备开始克隆 Client client = new Client(concretePrototype); ConcretePrototypeA concretePrototypeClone = (ConcretePrototypeA) client.startClone(concretePrototype); System.out.println(concretePrototypeClone); System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getHobbies()); System.out.println("原对象中的引用类型地址值:" + concretePrototype.getHobbies()); System.out.println("对象地址比较:"+(concretePrototypeClone.getHobbies() == concretePrototype.getHobbies()));
运行结果
从测试结果看出 hobbies 的引用地址是相同的,意味着复制的不是值,而是引用的地址。 这 样 的 话 , 如 果 我 们 修 改 任 意 一 个 对 象 中 的 属 性 值 , concretePrototype 和 concretePrototypeCone 的 hobbies 值都会改变。这就是我们常说的浅克隆。只是完整 复制了值类型数据,没有赋值引用对象。
深度克隆
我们换一个场景,大家都知道齐天大圣。首先它是一只猴子,有七十二般变化,把一根毫毛就可以吹出千万个泼猴,手里还拿着金箍棒,金箍棒可以变大变小。这就是我们耳 熟能详的原型模式的经典体现。
创建猴子Monkey类
public class Monkey { public int height; public int weight; public Date birthday; }
创建金箍棒类
public class JinGuBang implements Serializable { public float h = 100; public float d = 10; public void big(){ this.d *= 2; this.h *= 2; } public void small(){ this.d /= 2; this.h /= 2; } }
创建对象齐天大圣类
public class QiTianDaSheng extends Monkey implements Cloneable,Serializable { public JinGuBang jinGuBang; public QiTianDaSheng(){ //只是初始化 this.birthday = new Date(); this.jinGuBang = new JinGuBang(); } @Override protected Object clone() throws CloneNotSupportedException { return this.deepClone(); } public Object deepClone(){ try{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); QiTianDaSheng copy = (QiTianDaSheng)ois.readObject(); copy.birthday = new Date(); return copy; }catch (Exception e){ e.printStackTrace(); return null; } } public QiTianDaSheng shallowClone(QiTianDaSheng target){ QiTianDaSheng qiTianDaSheng = new QiTianDaSheng(); qiTianDaSheng.height = target.height; qiTianDaSheng.weight = target.height; qiTianDaSheng.jinGuBang = target.jinGuBang; qiTianDaSheng.birthday = new Date(); return qiTianDaSheng; }
测试类
QiTianDaSheng qiTianDaSheng = new QiTianDaSheng(); try { QiTianDaSheng clone = (QiTianDaSheng)qiTianDaSheng.clone(); System.out.println("深克隆:" + (qiTianDaSheng.jinGuBang == clone.jinGuBang)); } catch (Exception e) { e.printStackTrace(); } QiTianDaSheng q = new QiTianDaSheng(); QiTianDaSheng n = q.shallowClone(q); System.out.println("浅克隆:" + (q.jinGuBang == n.jinGuBang));
运行结果