原型模式Prototype

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

下面我克隆一个类,并修改名字和年龄,看看有什么变化

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();
    }
原文地址:https://www.cnblogs.com/hnhcc39/p/2612239.html