• 详解设计模式:原型模式


    原型模式(Prototype Pattern) ,是 GoF 的 23 种设计模式的一种,是用于创建重复的对象,同时又能保证性能。属于创建型模式,提供创建对象的最佳方式。

    原型(Prototype),在制造业中通常是指大批量生产开始之前研发出的概念模型,并基于各种参数指标对其进行检验,如果达到了质量要求,即可参照这个原型进行批量生产。原型模式达到以原型实例创建副本实例的目的即可,并不需要知道其原始类,也就是说,原型模式可以用对象创建对象,而不是用类创建对象,以此达到效率的提升。

    本篇内容包括:关于原型模式、原型模式-浅拷贝实现、原型模式-深拷贝实现



    一、关于原型模式

    1、关于原型模式

    原型模式(Prototype Pattern) ,是 GoF 的 23 种设计模式的一种,是用于创建重复的对象,同时又能保证性能。属于创建型模式,提供创建对象的最佳方式。

    原型(Prototype),在制造业中通常是指大批量生产开始之前研发出的概念模型,并基于各种参数指标对其进行检验,如果达到了质量要求,即可参照这个原型进行批量生产。原型模式达到以原型实例创建副本实例的目的即可,并不需要知道其原始类,也就是说,原型模式可以用对象创建对象,而不是用类创建对象,以此达到效率的提升。

    2、关于原型模式的构成

    原型模式包含如下角色:

    • 抽象原型类(Prototype):规定了具体原型对象必须实现的 clone() 方法。抽象原型类是定义具有克隆自己的方法接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口。
    • 具体原型类(ConcretePrototype):实现抽象原型类的 clone() 方法,它是可被复制的对象。
    • 访问类(Client):使用具体原型类中的 clone() 方法来复制新的对象。
    3、浅拷贝与深拷贝

    原型模式的使用需要注意浅拷贝与深拷贝的问题

    • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
    • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

    二、原型模式-浅拷贝实现

    1、浅拷贝

    浅拷贝,即调用 clone 对象拷贝内存中的数据时,要注意拷贝的是基础数据类型,对于数组,集合,自定义类等引用数据类型仅拷贝地址,会造成所有的对象都持有同一个内存地址的引用成员。

    • 基础数据类型:如果类中全部是基础数据类型,使用 clone 可以将该类完整的复制一份;
    • 引用数据类型:如果类中有引用类型成员,只是拷贝该成员的地址,所有的拷贝创建的原型模式实例对象都持有同一个引用,如果修改该引用成员的值,所有的原型对象实例的值都会跟着修改;
    2、浅拷贝实现

    # Cloneable 抽象原型类

    Java 中的 Object 类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是可以看作抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类

    # Realizetype 具体原型类

    public class Realizetype implements Cloneable {
    
        private Integer a;
        private Integer b;
    
        public Integer getA() {
            return a;
        }
    
        public void setA(Integer a) {
            this.a = a;
        }
    
        public Integer getB() {
            return b;
        }
    
        public void setB(Integer b) {
            this.b = b;
        }
    
        public Realizetype() {
            System.out.println("具体的原型对象创建完成!");
        }
    
        @Override
        protected Realizetype clone() throws CloneNotSupportedException {
            System.out.println("具体原型复制成功!");
            return (Realizetype) super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    # Client 访问测试类

    public class Client {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Realizetype r1 = new Realizetype();
            r1.setA(10);
            r1.setB(11);
            Realizetype r2 = r1.clone();
    				// 两者数据分别为 false 和 true 对象都持有同一个内存地址的引用成员
            System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
            System.out.println("对象r1和r2是同一个对象?" + (r1.getA() == r2.getA()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    三、原型模式-深拷贝实现

    1、深拷贝

    深拷贝,深拷贝时需要在 clone 方法中 , 调用引用数据类型本身的 clone 对象 , 在将其赋值给被拷贝的原型模式实例对象。

    实现深拷贝有两种方法:

    • 序列化该对象,然后反序列化回来,就能得到一个新的对象了。

      序列化:将对象写入到IO流中; 反序列化:从IO流中恢复对象 序列化机制允许将实现序列化的java对象转化为字节序列,这些字节序列可以保存到磁盘或者网络传输上,以达到以后恢复成原来的对象,序列化机制使得对象可以脱离程序的运行而独立存在。

    • 继续利用 clone() 方法,对该对象的引用类型变量再实现一次 clone() 方法。

    2、深拷贝实现(序列化方式)

    这里我们使用序列化的方式来实现深拷贝

    # Realizetype 实现 Serializable 序列化接口

    # Client

    import java.io.*;
    
    public class Client {
    
        public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
            Realizetype r1 = new Realizetype();
            r1.setA(10);
            r1.setB(11);
    
            //创建对象输出流对象
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/lizhengi/test/b.txt"));
            //将c1对象写出到文件中
            oos.writeObject(r1);
            oos.close();
    
            //创建对象出入流对象
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/lizhengi/test/b.txt"));
            //读取对象
            Realizetype r2  = (Realizetype) ois.readObject();
    
          	// 两者数据都为 false 说明对象持有不同的内存地址的引用成员,完成深拷贝
            System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
            System.out.println("对象r1和r2是同一个对象?" + (r1.getA() == r2.getA()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    Java版直播商城免 费 搭 建:电商、小程序、三级分销及免 费 搭 建,平台规划与营销策略全掌握
    2023年全国职业院校技能大赛信息安全管理与评估网络安全渗透任务书
    【面经】美团大数据开发面经
    mysqlclient在django启动时报错: Did you install mysqlclient?
    初识 Jenkins 持续集成
    python通过自相关对两个时序数据进行匹配、对时
    如何管理数据湖中的小文件
    Docker 安装Elasticsearch、Kibana、Logstash(宝塔linux)
    LeetCode904. 水果成篮
    transition和animation的区别?
  • 原文地址:https://blog.csdn.net/weixin_45187434/article/details/128075439