Java设计模式(5)之原型模式

原型模式:

顾名思义。将一个对象当作原型,通过对象克隆的方式复制,创建出更多与原型对象相同类型的对象。

类型:

创建型模式

原型对象关系图:

这里写图片描述

原型对象的3个角色:

  1. 客户(Client)角色:客户类提出创建对象的请求。
  2. 抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
  3. 具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

首先是一个简单的示例:

创建一个用于测试深浅克隆问题的类:

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Test {
}

创建Prototype接口对象

/**
 * Create by zhaihongwei on 2018/3/14
*
 * 提供一个供所有需要进行克隆操作的接口
 */
public interface Prototype {
    Object clone();
}

创建具体需要克隆的对象ConcretePrototype

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class ConcretePrototype implements Prototype {

    // test1 和 test2 和 test仅用来测试
    private int test1;
    private String test2;
    private Test test;

    public Test getTest() {
        return test;
    }

    public void setTest(Test test) {
        this.test = test;
    }

    public int getTest1() {
        return test1;
    }

    public void setTest1(int test1) {
        this.test1 = test1;
    }

    public String getTest2() {
        return test2;
    }

    public void setTest2(String test2) {
        this.test2 = test2;
    }

    @Override
    public ConcretePrototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setTest1(this.test1);
        concretePrototype.setTest(this.test);
        concretePrototype.setTest2(this.test2);
        return concretePrototype;
    }

}

创建Client对象

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Client {

    private Prototype prototype;

    public Client(Prototype prototype){
        this.prototype = prototype;
    }

    public Prototype startClone(Prototype concretePrototype) {
        return (Prototype) concretePrototype.clone();
    }
}

测试:

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class PrototypeTest {

    public static void main(String[] args) {

        // 创建一个具体的需要克隆的对象
        ConcretePrototype concretePrototype = new ConcretePrototype();
        // 填充属性,方便测试
        concretePrototype.setTest1(1);
        concretePrototype.setTest2("prototype");
        Test test = new Test();
        concretePrototype.setTest(test);
        System.out.println(concretePrototype);

        // 创建Client对象,准备开始克隆
        Client client = new Client(concretePrototype);
        ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
        System.out.println(concretePrototypeClone);

        System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
        System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
        System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));

    }
}

测试结果:

simple.ConcretePrototype@606d8acf
simple.ConcretePrototype@470e2030
克隆对象中的引用类型地址值:simple.Test@3fb4f649
原对象中的引用类型地址值:simple.Test@3fb4f649
没有深克隆:true

改造:

Java中已经提供了一个方便我们进行clone操作的接口Cloneable,我们已经不需要自己手动提供Prototype接口类了

浅克隆案例:

创建一个用于测试深浅克隆问题的类:

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Test {
}

创建具体需要克隆的对象ConcretePrototype

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class ConcretePrototype implements Cloneable {

    // test1 和 test2 仅用来测试
    private int test1;
    private String test2;
    private Test test;

    public Test getTest() {
        return test;
    }

    public void setTest(Test test) {
        this.test = test;
    }

    public int getTest1() {
        return test1;
    }

    public void setTest1(int test1) {
        this.test1 = test1;
    }

    public String getTest2() {
        return test2;
    }

    public void setTest2(String test2) {
        this.test2 = test2;
    }

    public Object clone() throws CloneNotSupportedException {
        ConcretePrototype concretePrototype = (ConcretePrototype) super.clone();
        return concretePrototype;
    }

}

创建Client类

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Client {

    private ConcretePrototype concretePrototype;

    public Client(ConcretePrototype concretePrototype){
        this.concretePrototype = concretePrototype;
    }

    public ConcretePrototype startClone(ConcretePrototype concretePrototype) throws CloneNotSupportedException {
        return (ConcretePrototype) concretePrototype.clone();
    }
}

测试类:

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class PrototypeTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        // 创建一个具体的需要克隆的对象
        ConcretePrototype concretePrototype = new ConcretePrototype();
        // 填充属性,方便测试
        concretePrototype.setTest1(1);
        concretePrototype.setTest2("prototype");
        Test test = new Test();
        concretePrototype.setTest(test);
        System.out.println(concretePrototype);

        // 创建Client对象,准备开始克隆
        Client client = new Client(concretePrototype);
        ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
        System.out.println(concretePrototypeClone);

        System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
        System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
        System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));

    }
}

测试结果:

shallow.ConcretePrototype@69222c14
shallow.ConcretePrototype@782830e
克隆对象中的引用类型地址值:shallow.Test@470e2030
原对象中的引用类型地址值:shallow.Test@470e2030
没有深克隆:true

结论:

从结果可以看出对象已经进行了复制,同时也看出了原型模式存在的一个问题,引用类型的对象没有进行复制,而是将引用的地址赋值了,即深克隆和浅克隆问题。

浅克隆:

只负责克隆按值传递的数据(基本数据类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。

深克隆:

除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。

深克隆案例:

创建一个用于测试深浅克隆问题的类:(需要实现Serializable接口)

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Test implements Serializable{
}

创建具体需要克隆的对象ConcretePrototype(需要实现Serializable接口)

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class ConcretePrototype implements Cloneable,Serializable {

    // test1 和 test2 仅用来测试
    private int test1;
    private String test2;
    private Test test;

    public Test getTest() {
        return test;
    }

    public void setTest(Test test) {
        this.test = test;
    }

    public int getTest1() {
        return test1;
    }

    public void setTest1(int test1) {
        this.test1 = test1;
    }

    public String getTest2() {
        return test2;
    }

    public void setTest2(String test2) {
        this.test2 = test2;
    }

    // 深克隆
    public  Object deepClone() throws IOException, ClassNotFoundException{
        //将对象写到流里
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流里读回来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

}

创建Client类

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class Client {

    private ConcretePrototype concretePrototype;

    public Client(ConcretePrototype concretePrototype){
        this.concretePrototype = concretePrototype;
    }

    public ConcretePrototype startClone(ConcretePrototype concretePrototype) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        return (ConcretePrototype) concretePrototype.deepClone();
    }
}

测试类:

/**
 * Create by zhaihongwei on 2018/3/14
 */
public class PrototypeTest  {

    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {

        // 创建一个具体的需要克隆的对象
        ConcretePrototype concretePrototype = new ConcretePrototype();
        // 填充属性,方便测试
        concretePrototype.setTest1(1);
        concretePrototype.setTest2("prototype");
        Test test = new Test();
        concretePrototype.setTest(test);
        System.out.println(concretePrototype);

        // 创建Client对象,准备开始克隆
        Client client = new Client(concretePrototype);
        ConcretePrototype concretePrototypeClone = (ConcretePrototype) client.startClone(concretePrototype);
        System.out.println(concretePrototypeClone);

        System.out.println("克隆对象中的引用类型地址值:" + concretePrototypeClone.getTest());
        System.out.println("原对象中的引用类型地址值:" + concretePrototype.getTest());
        System.out.println("没有深克隆:"+(concretePrototypeClone.getTest() == concretePrototype.getTest()));

    }
}

测试结果:

deep.ConcretePrototype@69222c14
deep.ConcretePrototype@27f674d
克隆对象中的引用类型地址值:deep.Test@1d251891
原对象中的引用类型地址值:deep.Test@16b4a017
没有深克隆:false

从结果可以看出Test对象已经不是原来的地址值了,说明Test对象也进行了重新创建。

深克隆的原理:

  • 利用序列化实现深度克隆,把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
  • 在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。

个人总结:

至此已经学完了5中创建型模式,下面将继续学习,结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。加油!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值