设计模式之原型模式(创建型模式)

本文详细介绍了原型模式中的浅克隆和深克隆概念,包括它们的区别、实现方式,并提供了一个通用的工具类来简化克隆操作。通过实例和代码演示了如何在Java中使用Cloneable与Serializable接口进行对象克隆。
摘要由CSDN通过智能技术生成

原型模式-Prototype Pattern

可以通过一个原型对象克隆出多个一模一样的对象,该模式称之为原型模式。

克隆

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

克隆

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

实现浅克隆的对象需要实现Cloneable接口

对象需要重写Object中的clone()方法,将方法权限设置为Public即可,然后方法体内调用Object的clone()方法。

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

实现深克隆的对象需要实现Serializable接口

public Object deepClone() throws Exception { 
    //将对象写入流中
    ByteArrayOutputStream bos=new ByteArrayOutputStream(); 
    ObjectOutputStream oos=new ObjectOutputStream(bos); 
    oos.writeObject(this); 
    //将对象从流中取出
    ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray()); 
    ObjectInputStream ois=new ObjectInputStream(bis);
    return ois.readObject(); 
}

由于以上克隆操作都需要在对象中添加对应方法,可以考虑提取一个工具类来简化操作。

下面附上浅克隆和深克隆的工具类代码

import java.io.*;
import java.lang.reflect.Field;


/**
 * @author wenbin
 * @date 2022/3/14 11:42
 */
public class CloneUtil {

    /**
     * <p>浅克隆 将传入的对象克隆一份返还</p>
     * 泛型参数只能接受实现Cloneable接口的类
     *
     * @param obj 要克隆的对象
     * @param <T> 该对象类型
     * @return 克隆出的对象
     */
    public static <T extends Cloneable> T shallowCloneObject(T obj) {
        //获取要克隆的对象的Class对象
        Class<? extends Cloneable> clazz = obj.getClass();
        //拿到所有属性字段
        Field[] fields = clazz.getDeclaredFields();
        //声明出目标对象
        T cloneObj = null;
        try {
            //实例化一个目标对象
            cloneObj = (T) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            //遍历传入的对象的所有属性的数组
            for (Field field : fields) {
                //设置该属性可见
                field.setAccessible(true);
                //拿到该属性的名称
                String name = field.getName();
                //拿到该属性的值
                Object o = field.get(obj);
                //赋值给目标对象
                field.set(cloneObj, o);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回目标对象
        return cloneObj;
    }


    /**
     * <p>深克隆 将传入的对象克隆一份返还</p>
     * 泛型参数只能接受实现Serializable接口的类
     *
     * @param obj 要克隆的对象
     * @param <T> 该对象类型
     * @return 克隆出的对象
     */
    public static <T extends Serializable> T deepCloneObject(T obj) {
        //声明出目标对象
        T cloneObj = null;
        //在try,catch块外声明出输出输入流对象,用于finally里确保流的关闭
        ObjectOutputStream obs = null;
        ObjectInputStream ois = null;
        try {
            //创建字节数组输出流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            //将字节数组输出流放入对象输出流中
            obs = new ObjectOutputStream(out);
            //将传入的对象写到流中
            obs.writeObject(obj);
            //创建字节数组输入流,并把刚才流中的对象放入进来
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            //将字节数组输入流放入对象输入流中
            ois = new ObjectInputStream(ios);
            //读取流中的数据输入进来并赋值给目标对象,至此,克隆结束
            cloneObj = (T) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                //这里进行判空关闭 关闭外层流 里面包裹的流也会被自动关闭
                if (obs != null) {
                    obs.close();
                }
                if (ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //返回目标对象
        return cloneObj;
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值