• 设计模式-原型模式-浅克隆和深克隆在Java中的使用示例


    场景

    设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例:

    设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例_霸道流氓气质的博客-CSDN博客

    设计模式-单例模式-饿汉式单例模式、懒汉式单例模式、静态内部类在Java中的使用示例:

    设计模式-单例模式-饿汉式单例模式、懒汉式单例模式、静态内部类在Java中的使用示例_霸道流氓气质的博客-CSDN博客

    上面讲了工厂模式和单例模式在Java中的示例,下面将原型模式的示例。

    原型模式(Prototype Pattern)

    原型模式是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

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

    原型模式主要适用于以下场景:

    1、类初始化消耗资源较多。

    2、使用new生成一个对象需要非常繁琐的过程(数据准备、访问权限等)。

    3、构造函数比较复杂。

    4、在循环体重产生大量对象。

    具体举例:

    一个对象需要在一个高代价的数据库操作之后被创建,我们可以缓存该对象,在下一个请求时返回它的克隆,在需要

    的时候更新数据库,以此来减少数据库调用。

    注:

    博客:
    霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
    关注公众号
    霸道的程序猿
    获取编程相关电子书、教程推送与免费下载。

    实现

    浅克隆-复制过程自己实现

    先创建原型Prototype

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. /**
    3.  * 原型Prototype接口
    4.  */
    5. public interface Prototype {
    6.     Prototype clone();
    7. }

    创建具体需要克隆的类ConcretePrototypeA 

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. import java.io.*;
    3. import java.util.List;
    4. /**
    5.  * 需要克隆的类
    6.  */
    7. public class ConcretePrototypeA implements Prototype{
    8.     private int age;
    9.     private String name;
    10.     private List hobbies;
    11.     public int getAge() {
    12.         return age;
    13.     }
    14.     public void setAge(int age) {
    15.         this.age = age;
    16.     }
    17.     public String getName() {
    18.         return name;
    19.     }
    20.     public void setName(String name) {
    21.         this.name = name;
    22.     }
    23.     public List getHobbies() {
    24.         return hobbies;
    25.     }
    26.     public void setHobbies(List hobbies) {
    27.         this.hobbies = hobbies;
    28.     }
    29.     @Override
    30.     public ConcretePrototypeA clone() {
    31.         //浅克隆-复制过程自己实现
    32.         ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
    33.         concretePrototype.setAge(this.age);
    34.         concretePrototype.setName(this.name);
    35.         concretePrototype.setHobbies(this.hobbies);
    36.         return concretePrototype;
    37.     }
    38. }

    创建Client类

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. public class Client {
    3.     private Prototype prototype;
    4.     public Client(Prototype prototype){
    5.         this.prototype = prototype;
    6.     }
    7.     public Prototype startClone(Prototype concretePrototype){
    8.         return concretePrototype.clone();
    9.     }
    10. }

    测试代码如下

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. import java.util.ArrayList;
    3. public class ProtoTypeTest {
    4.     public static void main(String[] args) {
    5.         //创建一个具体的需要克隆的对象
    6.         ConcretePrototypeA concretePrototype = new ConcretePrototypeA();
    7.         //填充属性,方便测试
    8.         concretePrototype.setAge(20);
    9.         concretePrototype.setName("霸道的程序猿");
    10.         concretePrototype.setHobbies(new ArrayList());
    11.         System.out.println(concretePrototype);
    12.         //创建client对象,准备开始克隆
    13.         Client client = new Client(concretePrototype);
    14.         ConcretePrototypeA concretePrototypeClone = (ConcretePrototypeA) client.startClone(concretePrototype);
    15.         System.out.println(concretePrototypeClone);
    16.         System.out.println(concretePrototype.getHobbies() == concretePrototypeClone.getHobbies());
    17.     }
    18. }

    运行测试代码

    从测试结果看,hobbies的引用地址是相同的,意味着复制的不是值,而是引用的地址。

    这样的话,如果我们修改任意一个对象的属性值,则concretePrototype和concretePrototypeClone的hobbies

    值都会改变,这就是浅克隆。

    浅克隆-调用jdk现成api-clone方法

    只需要实现Cloneable接口,重写clone方法,此处clone方法可以改成任意名称,因为Cloneable接口是个空接口,

    可以任意定位实现类的方法,此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法。

    在Object类中clone()是native的,是底层C实现的,它直接操作内存中的二进制流,特别是复制大对象时,性能的

    差别很明显。

    修改clone方法

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. import java.io.*;
    3. import java.util.List;
    4. /**
    5.  * 需要克隆的类
    6.  */
    7. public class ConcretePrototypeA implements Prototype,Cloneable{
    8.     private int age;
    9.     private String name;
    10.     private List hobbies;
    11.     public int getAge() {
    12.         return age;
    13.     }
    14.     public void setAge(int age) {
    15.         this.age = age;
    16.     }
    17.     public String getName() {
    18.         return name;
    19.     }
    20.     public void setName(String name) {
    21.         this.name = name;
    22.     }
    23.     public List getHobbies() {
    24.         return hobbies;
    25.     }
    26.     public void setHobbies(List hobbies) {
    27.         this.hobbies = hobbies;
    28.     }
    29.     @Override
    30.     public ConcretePrototypeA clone() {
    31.         //浅克隆-调用jdk现成的api,只需要实现Cloneable接口接口
    32.         try{
    33.             return (ConcretePrototypeA) super.clone();
    34.         } catch (CloneNotSupportedException e) {
    35.             e.printStackTrace();
    36.             return null;
    37.         }
    38.     }
    39. }

    此时也是浅克隆。下面介绍深克隆。

    深克隆

    将一个对象复制之后,不论是基本数据类型还有引用类型,都是重新创建的。

    深克隆是通过实现Serializable读取二进制流。

    1. package com.ruoyi.demo.designPattern.prototypePattern;
    2. import java.io.*;
    3. import java.util.List;
    4. /**
    5.  * 需要克隆的类
    6.  */
    7. public class ConcretePrototypeA implements Prototype,Cloneable,Serializable{
    8.     private int age;
    9.     private String name;
    10.     private List hobbies;
    11.     public int getAge() {
    12.         return age;
    13.     }
    14.     public void setAge(int age) {
    15.         this.age = age;
    16.     }
    17.     public String getName() {
    18.         return name;
    19.     }
    20.     public void setName(String name) {
    21.         this.name = name;
    22.     }
    23.     public List getHobbies() {
    24.         return hobbies;
    25.     }
    26.     public void setHobbies(List hobbies) {
    27.         this.hobbies = hobbies;
    28.     }
    29.     @Override
    30.     public ConcretePrototypeA clone() {
    31.         //深克隆-方法得实现可序列化,Serializable
    32.         try {
    33.             //序列化
    34.             ByteArrayOutputStream bos = new ByteArrayOutputStream();
    35.             ObjectOutputStream oos = new ObjectOutputStream(bos);
    36.             //将当前对象以对象流的方式输出
    37.             oos.writeObject(this);
    38.             //反序列化
    39.             ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    40.             ObjectInputStream ois = new ObjectInputStream(bis);
    41.             ConcretePrototypeA copy = (ConcretePrototypeA) ois.readObject();
    42.             return  copy;
    43.         } catch (Exception e) {
    44.             e.printStackTrace();
    45.             return null;
    46.         }
    47.     }
    48. }

    此时再运行测试代码

  • 相关阅读:
    Linux停止Java服务
    【upload靶场17-21】二次渲染、条件竞争、黑白名单绕过
    prometheus 原理(架构,promql表达式,描点原理)
    【MySQL】表复制,去重,合并查询
    【Rust 基础篇】Rust动态大小类型:理解动态大小类型与编写安全的代码
    (三)Python Range循环
    linux获取磁盘信息
    172版本关闭背钻后自动添加反盘和禁布的功能
    基于simulink的Passive anti-islanding-UVP/OVP and UFP/OFP被动反孤岛模型仿真
    别再乱看教程了!从源码剖析JVM类加载机制,打通双亲委派机制!
  • 原文地址:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127576328