首页 > 其他分享 >23种设计模式-原型设计模式介绍加实战

23种设计模式-原型设计模式介绍加实战

时间:2022-11-05 16:57:23浏览次数:55  
标签:account 克隆 23 对象 clone member 原型 设计模式

1、描述

用原型实例指定创建对象的种类,并且通过拷贝这些原型对象的属性来创建新的对象。通俗点的意思就是一个对象无需知道任何创建细节就可以创建出另外一个可定制的对象。可以简单看作为复制、粘贴操作。

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆

克隆对象的属性和原对象完全相同,基本类型的属性属于值传递,改变一个对象的值,另一个不会受影响。对于引用数据类型的属性,仍指向原有属性所指向的对象的内存地址。引用类型是传递引用,指向同一片内存空间,改变一个对象的引用类型的值,另一个对象也会随之改变。但是这里需要注意 String 类型却是一个特殊,String虽然属于引用类型,但是 String 类是不可改变的,它是一个常量,一个对象调用 clone 方法,克隆出一个新对象,这时候两个对象的同一个 String 类型的属性是指向同一片内存空间的,但是如果改变了其中一个,会产生一片新的内存空间,此时该对象的这个属性的引用将指向这片新的内存空间,此时两个对象的String类型的属性指向的就是不同的2片内存空间,改变一个不会影响到另一个,可以当做基本类型来使用。

  • 深克隆

克隆对象的所有属性都会被克隆,不再指向原有对象地址。

2、适用性

该设计模式使用场景很广泛,日常开发中难免有操作某个对象时又不想影响原有对象的情况,具体还需要看业务需求使用浅克隆或者是深克隆。

3、实现逻辑

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

Java 中通过 Object 类中提供的 clone() 方法和 Cloneable 接口来实现浅克隆,clone() 方法由 native 关键字修饰,通过本地方法拷贝地址值来实现,不但效率高还免去我们手动实现的烦恼。 Cloneable 接口充当抽象原型类,而我们实现了 Cloneable 接口的子实现类就是具体的原型类。

需要注意由于 Object 本身没有实现 Cloneable 接口,所以不重写 clone 方法并且进行调用的话会发生 CloneNotSupportedException 异常。

4、实战代码

4.1 浅克隆

/**
 * 原型类引用类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-05 15:29:57
 */
@Setter
@Getter
@ToString
public class Account {
    private String name;
}

/**
 * 具体的原型类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-10-28 17:00:11
 */
@Getter
@Setter
@ToString
public class Member implements Cloneable {

    private int id;

    private String name;

    private Account account;

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

/**
 * 测试类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-05 15:34:36
 */
public class ShallowClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        Account account = new Account();
        account.setName("account");

        Member member = new Member();
        member.setId(1);
        member.setName("member");
        member.setAccount(account);

        Member cloneMember = member.clone();

        // clone 对象与原对象的比较
        System.out.println(cloneMember == member);
        System.out.println(cloneMember.getId() == member.getId());
        System.out.println(cloneMember.getAccount() == member.getAccount());
        System.out.println(cloneMember.getName() == member.getName());

        // 修改 clone 对象属性
        account.setName("newAccount");
        cloneMember.setId(2);
        cloneMember.setName("newMember");

        // 查看原型对象
        System.out.println(member);
        System.out.println(cloneMember);
    }
}

执行结果:

从结果不难看出,我们得到的 clone 对象是一个新的对象,但是属性的值或者引用地址都是一样的。再修改 clone 对象后,基本类型的属性的值不会跟着修改, String 类型的属性由于自身特性指向了新的地址值,而我们 Account 类的属性,在 clone 对象的值被修改,两个对象的 account 属性都指向同一个内存地址值,所以会被一起修改。我在生产开发中需要注意原型模式对象引用属性谨慎操作。

4.2 深克隆

进行深克隆需要使用对象流。不用实现 Cloneable 接口,注意实现序列化接口 Serializable

/**
 * 原型类引用类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-05 15:29:57
 */
@Setter
@Getter
@ToString
public class Account implements Serializable {
    private String name;
}

/**
 * 具体的原型类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-10-28 17:00:11
 */
@Getter
@Setter
@ToString
public class Member implements Serializable {

    private int id;

    private String name;

    private Account account;
}

/**
 * 深克隆测试类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-05 16:26:57
 */
public class DeepClone {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Account account = new Account();
        account.setName("account");

        Member member = new Member();
        member.setId(1);
        member.setName("member");
        member.setAccount(account);

        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("XXX/member.txt"));
        //将c1对象写出到文件中
        oos.writeObject(member);
        oos.close();

        //创建对象出入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("XXX/member.txt"));
        //读取对象
        Member cloneMember = (Member) ois.readObject();
        //获取c2奖状所属学生对象
        Account newAccount = cloneMember.getAccount();
        newAccount.setName("newAccount");

        // 查看原型对象
        System.out.println(member);
        System.out.println(cloneMember);
    }
}

执行结果:

通过序列化和反序列化得到的对象地址值不同来达到目的

标签:account,克隆,23,对象,clone,member,原型,设计模式
From: https://www.cnblogs.com/eajur/p/16860554.html

相关文章

  • 2022-2023-1 20221421 《计算机基础与程序设计》第十周学习总结
    作业信息班级链接:https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求:https://www.cnblogs.com/rocedu/p/9577842.html#WEEK10作业目标:cpu调度,进程控制,先到先......
  • 1233. 全球变暖
    https://www.acwing.com/problem/content/1115/第一步,首先要考虑有多少个连通块,可以直接枚举每个点,对每个点进行一次搜索,与这个点连通的点共同构成一个连通块,数量用cn......
  • 常见的设计模式
    单例模式:单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在......
  • 2022-2023-1 20221401 《计算机基础与程序设计》第十周学习总结
    2022-2023-120221401《计算机基础与程序设计》第十周学习总结作业信息这个作业属于哪个课程<班级的链接>2022-2023-1-计算机基础与程序设计这个作业要求在哪......
  • 前端学画原型图(墨刀)
    前端学画原型图墨刀是一款国内较为出名的原型工具,常用于移动端,也可以做PC后台系统。安装简单、使用方便,制作完成后可以通过URL+密码发布,通过浏览器查看。如果需要......
  • 2023最新傻瓜式下载喜马拉雅音频文件,看不懂代码的你值得拥有
    傻瓜式教学如果还是学不会那不然,洗洗睡吧首先打开喜马拉雅网页版,随便点击一个节目,这里我用平时常听的“3分钟心理学”举例https://www.ximalaya.com/album/11848122......
  • 2022-2023-1 20201324《信息安全系统设计与实现(上)》第12章
    1块设备I/O缓冲区文件系统使用一系列I/O缓冲区作为块设备的缓存内存。当进程试图读取(dev,blk)标识的磁盘块时,它首先在缓冲区缓存中搜索分配给磁盘块的缓冲区。如果该缓......
  • 设计模式
    原型模式(Prototype)原型模式是一种创建型模式,它允许一个对象再创建另外一个可定制的对象,根本无需知道创建的细节。当直接创建对象的代价比较大时,则采用这种模式。在Java中......
  • 2022-2023-1 20221302《计算机基础与程序设计》第十周学习总结
    作业信息这个作业属于那个班级 https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求  https://www.cnblogs.com/rocedu/p/9577842.html#WEEK10作业目标......
  • B - K-th Number HDU - 6231 (二分 尺取)
    WindowsSource2017中国大学生程序设计竞赛-哈尔滨站题意给一个数组,在所有长度大于等于k的区间内,找出第\(k\)大的数,放到另一个数组中,然后在新数组中找到第M大的数。思......