【一天一个设计模式】原型模式的学习和理解

本文探讨了原型模式的两种实现方式,包括在类中实现克隆方法以及使用序列化进行克隆。通过示例代码展示了如何在User类和Prototype类中实现深拷贝,并分析了序列化克隆的优缺点,指出其可能带来的性能消耗问题。

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

最初的写法 在类中实现克隆方法 原型模式

可以重写equals和hashcode 反序列化出来的对象地址是不同的equals

User类

为了测试深拷贝,要在需要拷贝的类中加入引用类型

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class User implements Serializable {
    private String username;
    private String password;
}

Prototype类

package design.prototype;

import lombok.*;

import java.io.*;

@NoArgsConstructor  
@AllArgsConstructor  
@Setter  
@Getter  
@ToString  
public class Prototype implements PrototypeSup, Serializable {  
 private String name;  
 private User user;
//序列化操作  
@Override  
public Object clone() {  
    //深拷贝  

    //创建流对象        ByteArrayOutputStream bos = null;  
    ObjectOutputStream oos = null;  
    ByteArrayInputStream bis = null;  
    ObjectInputStream ois = null;  

    try {  
        //序列化  
        bos = new ByteArrayOutputStream();  
        oos = new ObjectOutputStream(bos);  
        oos.writeObject(this); //当前这个对象以对象流的方式输出  

        //反序列化            bis = new ByteArrayInputStream(bos.toByteArray());  
        ois = new ObjectInputStream(bis);  
        Prototype prototype = (Prototype) ois.readObject();  

        return prototype;  
    } catch (Exception e) {  
        e.printStackTrace();  
        return null;        } finally {  
        //关闭流  
        try {  
            bos.close();  
            oos.close();  
            bis.close();  
            ois.close();  
        } catch (Exception e2) {  
            System.out.println(e2.getMessage());  
        }  
    }  
}  
}

PrototypeSup类

public interface PrototypeSup   {
    public Object clone();
}

测试类

public static void main(String[] args) {
//测试开始  
User user = new User("zhangsan","132");  
//定义一个我们要拷贝的目标  
Prototype prototype = new Prototype("原型实例",user);  
//克隆  
Prototype proClone = (Prototype) prototype.clone();  
Prototype proClone3 = (Prototype) prototype.clone();  
System.out.println(proClone+" hashcode"+proClone.hashCode()+
"User"+proClone.getUser()+" hashcod"+proClone.getUser().hashCode());  
System.out.println(proClone3+" hashcode"+proClone3.hashCode()+
"User"+proClone3.getUser()+" hashcod"+proClone3.getUser().hashCode()); 
} 

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6aYFCgg-1666841383435)(file:///C:/Users/林巳洁/AppData/Roaming/marktext/images/2022-10-08-20-36-23-image.png?msec=1666841185120)]

第二种写法 将clone接口去除改成工具类 普通类想要克隆只需要序列化(实现序列化接口)就可以
public class ProTypeUtil{
    //序列化操作
    //传入想要拷贝的对象
    //传入的clazz需要和data是一个类
    public  static  <T> T ToClone(Object data,Class<T> clazz) {
        //深拷贝

        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(data); //当前这个对象以对象流的方式输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            T prototype=null;
            if (clazz.isInstance(data)){
                System.out.println("传入的class和类是相同的类型");
                System.out.println(clazz);
                prototype =  (T)ois.readObject();
            }

            return prototype;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }

        }
    }
}

将方法改成静态的 利用方法内的泛型以及多传入一个类型来解决问题


        //测试开始
        User user = new User("zhangsan","132");
        //定义一个我们要拷贝的目标
        Prototype prototype = new Prototype("原型实例",user);
        //克隆
        Prototype proClone = ProTypeUtil.ToClone(prototype,prototype.getClass());
        Prototype proClone1 =  ProTypeUtil.ToClone(prototype,Prototype.class);
        Prototype proClone2 = prototype;
        Prototype proClone3 = prototype ;
        System.out.println(proClone+" hashcode"+proClone.hashCode()+"User"+proClone.getUser()+" hashcod"+proClone.getUser().hashCode());
        System.out.println(proClone3+" hashcode"+proClone3.hashCode()+"User"+proClone3.getUser()+" hashcod"+proClone3.getUser().hashCode());

        //地址不相同
        System.out.println(proClone==proClone3);
        System.out.println(proClone2==proClone2);

类的获取用 .class 和 getclass 都可以实现,

至此我们完成了利用一个工具类就可以深拷贝一个实例,因为利用序列化和反序列化的原理,需要为所有用到的类和引用类型添加接口,

反序列化

缺点是 性能消耗较大

原理参考文章[(33条消息) 设计模式-原型模式(克隆羊多利看了都说好)_吾仄lo咚锵的博客-CSDN博客_多利设计模式

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值