创建型设计模式之二——原型模式

本文详细介绍了Java中的原型模式,包括为何使用原型模式、什么是深克隆和浅克隆,并通过实例展示了两者的区别。文章还探讨了深克隆的实现方式,如序列化,并提供了源码解析。同时,给出了如何在实际项目中应用原型模式的建议和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


用简单通俗的话来记录自己对架构的理解

1.为什么

(1)一种更高效的对象创建方式,利用原型对象来复制产生新的对象:这种方式的创建更高效,避免了new这种方式的耗时,当然,也可以避免耗时操作的创建(比如数据库的查询)
(2)特殊需求的要求,比如需求:对原始对象进行1,2,3步的处理,而在第4步却还要使用原始对象。
(3)架构需要:为了模块隔离对外暴露隔离API
比如Java中的ArrayList、Intent等

 @Override
    public Object clone() {
        return new Intent(this);
    }

  /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

**TODO:**实际上,此处有一个疑问,Intent为啥不像ArrayList使用Clone方式,使用堆内存直接复制?

2.是什么

上类图:

在这里插入图片描述

直白一点,就是为了更简单获取对象。
那么在java中的原型模式又分为深克隆和浅克隆;对于一个对象,其成员变量为基本数据和引用数据。浅克隆只是对象的引用的复制,而深克隆则是原始对象的引用数据进行申请内存空间,不是简单的对象的引用。

(1).深克隆

深克隆就是对于对象的基本数据进行复制,引用数据进行申请内存,复制对象数据,而引用指向是变化的。
深克隆的方式有很多种,对于Java中常用的是序列化。之所以序列化,是因为序列化本质是格式的转变,从对象——>序列化——>反序列化——>对象,这个对象是完全重新申请空间创建的。代码如下:

public class PrototypeUtil {
    /**
     * @description: 通过序列化获取一个深度克隆的对象
     * @param prototype
     * @return com.lmc.gp12380.pattern.prototype.Prototype
     * @date 2019/5/30 21:34
     * @author lmc
     */
    public static Prototype getSerializInstance(Prototype prototype){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(prototype);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Prototype copy = (Prototype)ois.readObject();
            bos.flush();
            bos.close();
            ois.close();
            return copy;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

当然,对于简单的对象,也有同学是循环使用Java中的Clone,只要是引用数据类型,都进行Clone的处理。这种方式太ugly和笨重,所以,不推荐。

(2).浅克隆

浅克隆就是对于成员变量复制,包括基本数据类型和引用数据类型。这样的话,引用数据类型的只是指针引用复制,实际指引对象是不变的。
Java中的实现是通过Cloneale的clone()方法。实际上Clone方法进行了优化,对于new()这个方法,只进行了内存申请的操作,效率要高很多,可以看源码解析。但是,它是如何实现的呢?ASM看源码:
在这里插入图片描述
难过的是字节码功底不够,我没咋看懂,回头再研究一下。

3.怎么用

思路:定义一个接口类,实现深浅克隆。

/**
 * 接口
 **/
public interface Prototype {

    /**
     * @description: 获取浅克隆对象
     * @return java.lang.Object
     * @date 2019/5/29 20:35
     * @author lmc
     */
    Prototype getShallowCloneInstance() throws CloneNotSupportedException;
    /**
     * @description: 获取深克隆对象
     * @return com.lmc.gp12380.pattern.prototype.Prototype
     * @date 2019/5/30 21:15
     * @author lmc
     */
    Prototype getDeepCloneInstance(Prototype prototype);

}

/**
*    序列化实现深克隆
*/

public class PrototypeUtil {
    /**
     * @description: 通过序列化获取一个深度克隆的对象
     * @param prototype
     * @return com.lmc.gp12380.pattern.prototype.Prototype
     * @date 2019/5/30 21:34
     * @author lmc
     */
    public static Prototype getSerializInstance(Prototype prototype){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(prototype);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Prototype copy = (Prototype)ois.readObject();
            bos.flush();
            bos.close();
            ois.close();
            return copy;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}


实现对象实现Clone方法,并暴露新的接口:

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

    public Prototype getShallowCloneInstance() throws CloneNotSupportedException {
        return (Prototype) clone();
    }```



4.源码解析

1.克隆比直接创建效率更高吗?
(1)实例:
对象的创建和克隆比对:

        long newObjectStart = System.currentTimeMillis();
        List<Student> newStudentList = new ArrayList<>();
        for (int i =0;i<10000;i++){
            Student student = new Student();
            student.setAge(10);
            student.setName("xl"+i);
            newStudentList.add(student);
        }
        Log.d("haha","newObjectCostTime:"+(System.currentTimeMillis() - newObjectStart));

        long cloneObjectStart = System.currentTimeMillis();
        List<Student> cloneStudentList = new ArrayList<>();
        Student student = new Student();
        for (int i =0;i<10000;i++){
            Student cloneStudent = (Student) student.clone();
            cloneStudent.setAge(10);
            cloneStudent.setName("xl"+i);
            cloneStudentList.add(student);
        }
        Log.d("haha","newObjectCostTime:"+(System.currentTimeMillis() - cloneObjectStart));

结果:

2021-02-19 00:21:57.075 9695-9695/xl.com.frameworkdesigndemo D/haha: 1000条数据newObjectCostTime:15
2021-02-19 00:21:57.081 9695-9695/xl.com.frameworkdesigndemo D/haha: 1000条数据cloneObjectCostTime:6
2021-02-19 00:22:26.204 9696-9696/xl.com.frameworkdesigndemo D/haha: 100条数据newObjectCostTime:4
2021-02-19 00:22:26.207 9696-9696/xl.com.frameworkdesigndemo D/haha: 100条数据cloneObjectCostTime:3

(2)本质原因:
从字节码指令集的解读对象创建的流程的解读:

5.巨人肩膀

https://www.cnblogs.com/programmerkaixin/p/10969745.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值