GOF23设计模式之原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能,它提供了一种创建对象的最佳方式。原型模式单独使用的比较少,较多的是结合工厂模式创建一些复杂的、创建开销比较大的对象,或者是复制一些经过处理、改变初始属性值的对象。

原型模式可以有两种实现方式,一是通过实现Cloneable接口,重写clone方法实现;二是通过序列化和反序列化方式实现。

一、Clone方式实现:

先创建一个原型类:

package com.minant.prototype;

import java.util.Date;
import java.util.Objects;

/**
 * @ClassName MyProto
 * @Description TODO 原形对象
 * @Author MinAnt
 * @Date 2020/5/20
 * @Version V1.0
 */
public class MyProto implements Cloneable {
    private String name;
    private ProtoTarget protoTarget;

    public MyProto() {
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public ProtoTarget getProtoTarget() {
        return protoTarget;
    }

    public void setProtoTarget(ProtoTarget protoTarget) {
        this.protoTarget = protoTarget;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MyProto)) return false;
        MyProto proto = (MyProto) o;
        return Objects.equals(getName(), proto.getName()) &&
                Objects.equals(getProtoTarget(), proto.getProtoTarget());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getName(), getProtoTarget());
    }

    @Override
    public String toString() {
        return "MyProto{" +
                "name='" + name + '\'' +
                ", protoTarget=" + protoTarget +
                '}';
    }
}

该类实现了Cloneable接口,并重写了Object类的clone方法。Cloneable为一个空接口,若不实现该接口则在调clone方法的时候会报出异常(CloneNotSupportedException),无法实现克隆操作。该类中还包含一个ProtoTarget对象,ProtoTarget类也实现了Cloneable接口,重写了clone方法。

package com.minant.prototype;

import java.util.Objects;

/**
 * @ClassName ProtoTarget
 * @Description TODO
 * @Author MinAnt
 * @Date 2020/5/20
 * @Version V1.0
 */
public class ProtoTarget implements Cloneable {
    private String msg;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public ProtoTarget(String msg) {
        this.msg = msg;
    }

    public ProtoTarget() {
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ProtoTarget)) return false;
        ProtoTarget that = (ProtoTarget) o;
        return Objects.equals(getMsg(), that.getMsg());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getMsg());
    }

    @Override
    public String toString() {
        return "ProtoTarget{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

测试类:

package com.minant.prototype;

/**
 * @ClassName TestProtoType
 * @Description TODO 测试原型模式
 * @Author MinAnt
 * @Date 2020/5/20
 * @Version V1.0
 */
public class TestProtoType {
    public static void main(String[] args) throws CloneNotSupportedException {
        MyProto proto = new MyProto();
        proto.setName("我是正版");
        proto.setProtoTarget(new ProtoTarget("aaa"));
        System.out.println(proto.toString());

        MyProto cpproto = (MyProto) proto.clone();
        System.out.println(cpproto.toString());

    }
}

结果:

看这个结果貌似没有什么问题,把原型对象复制了一份一模一样的对象出来。但实际上是有问题,下面就来修改下对象属性看下结果。

修改克隆对象中的ProtoTarget对象的属性后,原对象中的属性也跟着改变了,说明克隆对象的ProtoTarget属性和原对象中的这一属性还是指定在同一个内存地址。这种克隆称之为浅克隆。那么要想实现深克隆,就得把原型对象的所有类属性都克隆一遍,如下:

这也是为什么ProtoTarget也要实现Cloneable、重写clone方法的原因。如此以后,现查看结果:

这样就实现深克隆了。

二、序列化反序列化方式实现:

序列化的实现就需要类实现Serializable接口。

然后写测试类:

package com.minant.prototype;

import java.io.*;

/**
 * @ClassName TestProtoSeril
 * @Description TODO 序列化反序列化生成测试
 * @Author MinAnt
 * @Date 2020/5/21
 * @Version V1.0
 */
public class TestProtoSeril {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        MyProto proto = new MyProto();
        proto.setName("我是正版");
        proto.setProtoTarget(new ProtoTarget("aaa"));
        System.out.println(proto.toString());

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oout = new ObjectOutputStream(bout);
        oout.writeObject(proto);
        bout.close();
        bout.close();
        byte[] rs = bout.toByteArray();
        ByteArrayInputStream bin = new ByteArrayInputStream(rs);
        ObjectInputStream oin = new ObjectInputStream(bin);
        MyProto cpproto = (MyProto) oin.readObject();
        System.out.println(cpproto.toString());

        System.out.println("==============================");
        cpproto.getProtoTarget().setMsg("bbb");
        System.out.println(proto.toString());
        System.out.println(cpproto.toString());



    }
}

运行结果:

修改复制类不影响原型类。

 

最后我们可以来简单测试一下New创建和Clone创建之间的效率问题:

package com.minant.prototype;

/**
 * @ClassName ProtoPerformTest
 * @Description TODO 性能测试
 * @Author MinAnt
 * @Date 2020/5/21
 * @Version V1.0
 */
public class ProtoPerformTest {
    public static void testNew() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            ProtoPerForm form = new ProtoPerForm();
        }
        long end = System.currentTimeMillis();
        System.out.println("New 耗时:" + (end - start));
    }

    public static void testClone() throws CloneNotSupportedException {
        ProtoPerForm form = new ProtoPerForm();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            ProtoPerForm temp = (ProtoPerForm) form.clone();
        }
        long end = System.currentTimeMillis();
        System.out.println("Clone 耗时:" + (end - start));
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        testNew();
        testClone();
    }

}

class ProtoPerForm implements Cloneable {
    public ProtoPerForm() {
        // 模拟创建对象过程
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

结果:

由结果可看出,new的过程越复杂、耗时越多则两者效率差距会越大。

 

原型模式到此结束,本人能力有限,有不足之处还请各位不吝赐教。

Stay hungry stay foolish!加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值