原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。
下面我克隆一个类,并修改名字和年龄,看看有什么变化
package com.taobao.business; /** * 原型模式:创建型 */ public class Prototype { public static void main(String[] args) throws Exception { //先创建一个对象原型 Person p = new Person("张三",18); try { Person cloneP = (Person) p.clone(); System.out.println("原来的:" + p); System.out.println("克隆的:" + cloneP); cloneP.setName("李四"); //修改名字 cloneP.ageClass.update(); //修改年龄 System.out.println("修改后原来的:" + p); System.out.println("修改后克隆的:" + cloneP); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } /** * 浅拷贝 */ class AgeClass{ public long age; //修改age public void update(){ this.age *= 2; } @Override public String toString() { return "年龄:"+age; } } class Person implements Cloneable{ private String name; public AgeClass ageClass = new AgeClass(); public Person(String name, long age) { super(); this.name = name; this.ageClass.age = age; } //修改name public void setName(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); return person; } @Override public String toString() { return "姓名:"+name+","+ageClass; } }
输出的结果是:
原来的:姓名:张三,年龄:18
克隆的:姓名:张三,年龄:18
修改后原来的:姓名:张三,年龄:36
修改后克隆的:姓名:李四,年龄:36
为什么修改了克隆对象后,姓名改变了,但是年龄为什么原来那个对象也改变了?而且我定义的姓名是一个基础类型,而年龄是自定义的类型,这说明浅克隆是不能把复杂类型的值克隆出来的,那么如果解决呢?有人可能会想那把年龄那个类不要做成自定义类型不就可以了吗?但是现实情况可能不是一个年龄类呢?而且是一个其它的复杂类型呢?所以这就要采用深度克隆,把年龄类改成也实现Cloneable接口。
/** * 深拷贝 */ class AgeClass implements Cloneable{ public long age; //修改age public void update(){ this.age *= 2; } @Override protected Object clone() throws CloneNotSupportedException { return (AgeClass) super.clone(); } @Override public String toString() { return "年龄:"+age; } }
当然Person类的clone方法也要相应的改一下
@Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.ageClass = (AgeClass)ageClass.clone(); //深拷贝 return person; }
ok,现在运行一下,看看年龄克隆后是的引用还是把值克隆过去了?
原来的:姓名:张三,年龄:18
克隆的:姓名:张三,年龄:18
修改后原来的:姓名:张三,年龄:18
修改后克隆的:姓名:李四,年龄:36
可以了!现在的自定义类型也克隆过去了!而且把克隆对象改了,也不会对以前的对象有其它影响。
但是当这中自定义类型中如果又包含有很多个自定义类型呢?难道把每个类都改成实现Clone接口吗?那是不是太麻烦点了?这样的话,我们可以把对象序列化,当需要的时候再反序列化。
/** * 序列化 */ private static Object cloneObject(Object obj) throws Exception{ //把对象写入字节数组 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(obj); //从字节数组读取出对象 ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in =new ObjectInputStream(byteIn); return in.readObject(); }