原型模式

  • 先定义基本对象:

package com.whereta.prototype;

import java.io.Serializable;

/**
 * Vincent 创建于 2016/4/18.
 */
public class Company implements Cloneable,Serializable{
    /**
     * 公司名字
     */
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.whereta.prototype;

/**
 * Vincent 创建于 2016/4/18.
 * 用户对象
 */
public class User implements  Cloneable {
    /**
     * 用户年龄
     */
    private  int age;
    /**
     * 用户姓名
     */
    private String name;
    /**
     * 公司
     */
    private Company company;

    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 Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
package com.whereta.prototype;

import java.io.*;

/**
 * Vincent 创建于 2016/4/18.
 * 深度复制用户对象
 */
public class DeepUser implements Cloneable,Serializable{
    /**
     * 用户年龄
     */
    private int age;
    /**
     * 用户姓名
     */
    private String name;
    /**
     * 公司
     */
    private Company company;

    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 Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();

            ObjectOutputStream oo = new ObjectOutputStream(bo);

            oo.writeObject(this);        //read from stream
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());

            ObjectInputStream oi = new ObjectInputStream(bi);

            return (oi.readObject());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}


  • 使用原型模式之前先看下我们平时经常用的引用复制指向:

package com.whereta.prototype;

import com.alibaba.fastjson.JSON;

/**
 * Vincent 创建于 2016/4/18.
 * 此处是简单复制,即不同对象指向同一个引用地址
 */
public class SimpleCopyObject {

    public static void main(String[] args) {
        User user = new User();
        User user1 = user;

        System.out.println(user);
        System.out.println(user1);

        user.setAge(23);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(user1));


        user.setAge(24);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(user1));
    }


}
  • 输出结果:

Connected to the target VM, address: '127.0.0.1:55324', transport: 'socket'
com.whereta.prototype.User@6ba8fb1b
com.whereta.prototype.User@6ba8fb1b
{"age":23}
{"age":23}
{"age":24}
{"age":24}
Disconnected from the target VM, address: '127.0.0.1:55324', transport: 'socket'
  • 从输出结果可以看出:两个对象实际指向的是同一个地址,所以修改任何一个对象都可以引起另一个对象的改变

  • 现在看浅复制

package com.whereta.prototype;

import com.alibaba.fastjson.JSON;

/**
 * Vincent 创建于 2016/4/18.
 * 浅复制:只是复制基本数据类型,引用类型还是指向同一个地址
 */
public class ShallowClone {
    public static void main(String[] args) throws CloneNotSupportedException {


        Company company=new Company();
        company.setName("海信科技");

        User user=new User();
        user.setAge(22);
        user.setName("小明");
        user.setCompany(company);


        Object clone = user.clone();


        User user1= (User) clone;
        //此处可以看出,与简单复制不同的是:克隆之后的对象与源对象引用地址不同
        System.out.println(user);
        System.out.println(clone);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));

        System.out.println(user.getCompany());
        System.out.println(user1.getCompany());

        //此处可以看出,修改了公司名字,两个对象都修改了公司名字,所以引用的是同一个对象
        company.setName("sdfds");


        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));

        //此处测试:修改基本数据类型只会修改当前对象,不会修改克隆对象
        user.setAge(34);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));

    }
}
  • 输出结果:

com.whereta.prototype.User@6ef64f64
com.whereta.prototype.User@6cd66725
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
com.whereta.prototype.Company@2d75705e
com.whereta.prototype.Company@2d75705e
{"age":22,"company":{"name":"sdfds"},"name":"小明"}
{"age":22,"company":{"name":"sdfds"},"name":"小明"}
{"age":34,"company":{"name":"sdfds"},"name":"小明"}
{"age":22,"company":{"name":"sdfds"},"name":"小明"}
  • 从输出结果可以看出:克隆之后的对象与源对象指向了不同地址;但是引用对象(公司)还是指向了同一个地址,所以修改公司名字两个对象都会修改;但是修改基本类型数据不会修改克隆之后的对象数据


  • 深度克隆:

package com.whereta.prototype;

import com.alibaba.fastjson.JSON;

/**
 * Vincent 创建于 2016/4/18.
 * 深度复制:无论是基本数据类型还是引用类型,全部重新复制一份
 */
public class DeepClone {

    public static void main(String[] args) throws CloneNotSupportedException {
        Company company=new Company();
        company.setName("海信科技");

        DeepUser user=new DeepUser();
        user.setAge(22);
        user.setName("小明");
        user.setCompany(company);


        Object clone = user.clone();
        DeepUser user1= (DeepUser) clone;
        //此处可以看出,与简单复制不同的是:克隆之后的对象与源对象引用地址不同
        System.out.println(user);
        System.out.println(clone);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));
        //此处可以看出引用对象地址也是不一样的
        System.out.println(user.getCompany());
        System.out.println(user1.getCompany());

        //此处可以看出,修改了公司名字,不会修改克隆之后的对象公司名字
        company.setName("sdfds");


        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));

        //此处测试:修改基本数据类型只会修改当前对象,不会修改克隆对象
        user.setAge(34);

        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(clone));
    }

}
  • 输出结果:

com.whereta.prototype.DeepUser@3a5367af
com.whereta.prototype.DeepUser@1b033c7e
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
com.whereta.prototype.Company@71f84d01
com.whereta.prototype.Company@3e8f474f
{"age":22,"company":{"name":"sdfds"},"name":"小明"}
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
{"age":34,"company":{"name":"sdfds"},"name":"小明"}
{"age":22,"company":{"name":"海信科技"},"name":"小明"}
  • 从输出结果可以看出:克隆之后的引用对象也是与源对象引用对象地址不一样,所以深度克隆是完全的克隆!!

总结:


优点:

  • 当创建新的对象实例较为复杂时,可以简化对象创建过程,通过复制一个已有实例可以提高实例的创建效率。

  • 扩展性较好,原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程。

  • 原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

  • 可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。



参考文章:http://blog.csdn.net/yanbober/article/details/45363525

个人博客:http://www.whereta.com

你可能感兴趣的:(原型模式)