• 原型(克隆)模式


    思考原型(克隆)模式

    原型模式顾名思义通过一个接口实现快速创建对象,主要解决的问题就是创建重复对象,而这部分对象内容本身比较复杂,生成过程可能从库或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间。

    1.原型模式的本质

    原型模式的本质:克隆生成对象。

    克隆是手段,目的是生成新的对象实例。正是因为原型的目的是为了生成新的对象实例,原型模式通常是被归类为创建型的模式。

    原型模式也可以用来解决“只知接口而不知实现的问题”,使用原型模式,可以出现一种独特的“接口造接口”的景象,这在面向接口编程中很有用。同样的功能也可以考虑使用工厂来实现。

    另外,原型模式的重心还是在创建新的对象实例,至于创建出来的对象,其属性的值是否一定要和原型对象属性的值完全一样,这个并没有强制规定,只不过在目前大多数实现中,克隆出来的对象和原型对象的属性值是一样的。

    也就是说,可以通过克隆来创造值不一样的实例,但是对象类型必须一样。可以有部分甚至是全部的属性的值不一样,可以有选择性地克隆,就当是标准原型模式的一个变形使用吧。

    2.何时选用原型模式

    建议在以下情况时选用原型模式。

    • 在运行时动态地生成对象,而不是在编译时静态地创建对象。

    • 当创建对象的成本比复制现有对象的成本更高时。例如,创建一个数据库连接对象需要花费较长的时间和资源,但是复制一个现有连接对象的副本只需要很少的时间和资源。

    • 当需要避免直接暴露对象的创建细节时。使用原型模式可以将对象的创建逻辑封装在对象内部,而不需要让外部代码知道对象是如何创建的。

    3.优缺点

    原型模式的优点

    • 便于通过克隆方式创建复杂对象、也可以避免重复做初始化操作.不需要与类中所属的其他类耦合等。

    原型模式的缺点

    • 如果对象中包括了循环引用的克隆,以及类中深度使用对象的克隆,都会使此模式变得异常麻烦。

    4.原型模式的结构

    在这里插入图片描述

    • Prototype:声明一个克隆自身的接口,用来约束想要克隆自己的类,要求它们都要实现这里定义的克隆方法。
    • ConcretePrototype:实现 Prototype接口的类,这些类真正实现了克隆自身的功能。
    • Client:使用原型的客户端,首先要获取到原型实例对象,然后通过原型实例克隆自身来创建新的对象实例。

    5.实现

    原型模式(浅克隆)

    1.克隆接口

    /**
     * @description:需要克隆方法实现此接口
     */
    public interface OrderApi {
    
        /**
         * 克隆方法
         * @return
         */
        OrderApi clone();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.实现类

    /**
     * @description:个人订单
     */
    @Data
    @ToString
    public class PersonOrder implements OrderApi{
    
        /**
         * 用户名
         */
        private String personName;
        /**
         * 产品id
         */
        private Integer productId;
    
        private CompanyOrder companyOrder;
    
    
        /**
         * 克隆对象
         * @return
         */
        @Override
        public OrderApi clone() {
            PersonOrder personOrder = new PersonOrder();
            personOrder.setPersonName(this.personName);
            personOrder.setProductId(this.productId);
            personOrder.setCompanyOrder(this.companyOrder);
            return personOrder;
        }
    }
    
    /**
     * @description:公司订单
     */
    @Data
    @ToString
    public class CompanyOrder implements OrderApi{
    
        /**
         * 公司名
         */
        private String companyName;
        /**
         * 产品id
         */
        private Integer productId;
    
        /**
         * 克隆对象
         * @return
         */
        @Override
        public OrderApi clone() {
            CompanyOrder companyOrder = new CompanyOrder();
            companyOrder.setCompanyName(this.companyName);
            companyOrder.setProductId(this.productId);
            return companyOrder;
        }
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    3.测试类

    /**
     * @description:测试类
     */
    public class Client {
    
        public static void main(String[] args) {
    
            //公司订单对象
            CompanyOrder companyOrder = new CompanyOrder();
            companyOrder.setCompanyName("字节跳动");
            companyOrder.setProductId(10002);
    
            //个人订单对象
            PersonOrder personOrder = new PersonOrder();
            personOrder.setPersonName("张三");
            personOrder.setProductId(10001);
            personOrder.setCompanyOrder(companyOrder);
    
            System.out.println("个人订单原对象:"+personOrder);
            System.out.println("公司订单原对象:"+companyOrder);
            //克隆个人订单对象
            OrderApi personClone = personOrder.clone();
    
            System.out.println("个人订单克隆对象1:"+personClone);
            //修改公司订单对象的值
            companyOrder.setCompanyName("88888888888");
            System.out.println("公司订单原对象:"+companyOrder);
            //再次打印个人订单对象,发现值变了,是浅克隆
            System.out.println("个人订单克隆对象2:"+personClone);
        }
    }
    
    • 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

    4.结果
    在这里插入图片描述

    原型模式(深克隆)

    1.实现深度克隆只需克隆引用对象时,调用它自己的克隆方法,一直传递下去

    /**
     * 克隆对象
     * @return
     */
    @Override
    public OrderApi clone() {
        PersonOrder personOrder = new PersonOrder();
        personOrder.setPersonName(this.personName);
        personOrder.setProductId(this.productId);
        personOrder.setCompanyOrder((CompanyOrder) this.companyOrder.clone());
        return personOrder;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.结果
    在这里插入图片描述

    java提供的克隆

    1、浅克隆:对当前对象进行克隆,并克隆该对象所包含的8种基本数据类型和String类型属性(拷贝一份该对象并重新分配内存,即产生了新的对象);但如果被克隆的对象中包含除8中数据类型和String类型外的其他类型的属性,浅克隆并不会克隆这些属性(即不会为这些属性分配内存,而是引用原来对象中的属性)
    2、深克隆:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

    java浅克隆

    1.实现Cloneable接口
    2.重写clone方法

    /**
     * @description:个人订单
     */
    @Data
    @ToString
    public class PersonOrder2 implements Cloneable{
    
        /**
         * 用户名
         */
        private String personName;
        /**
         * 产品id
         */
        private Integer productId;
    
        private CompanyOrder2 companyOrder2;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    @Data
    @ToString
    public class CompanyOrder2 implements Cloneable{
    
        /**
         * 公司名
         */
        private String companyName;
        /**
         * 产品id
         */
        private Integer productId;
    
        @Override
    	public Object clone() {
    		Object obj=null;
    		try {
    			obj=super.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
    		return obj;
    	}
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.测试

    /**
     * @description:测试类
     */
    public class Client {
    
        public static void main(String[] args) throws CloneNotSupportedException {
    
            CompanyOrder2 companyOrder2 = new CompanyOrder2();
            companyOrder2.setCompanyName("字节跳动");
            companyOrder2.setProductId(10002);
    
            PersonOrder2 personOrder2 = new PersonOrder2();
            personOrder2.setPersonName("张三");
            personOrder2.setProductId(10001);
            personOrder2.setCompanyOrder2(companyOrder2);
            System.out.println("原对象:"+personOrder2);
    
            //java浅克隆
            Object clone = personOrder2.clone();
            System.out.println("克隆对象:"+clone);
            companyOrder2.setCompanyName("9999999999");
            System.out.println("克隆对象:"+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

    4.结果
    在这里插入图片描述

    可以看到,虽然克隆出来了一个一模一样的对象,但是修改原对象的属性,克隆的对象属性也改变了,这就是浅克隆,原对象和克隆对象的引用属性共同指向一个内存地址

    java深克隆

    1.实现深度克隆只需克隆引用对象时,调用它自己的克隆方法,一直传递下去,原理和上面的原型实现深克隆一样

    @Override
    protected Object clone() throws CloneNotSupportedException {
        PersonOrder2 clone = (PersonOrder2) super.clone();
        clone.setCompanyOrder2((CompanyOrder2) this.companyOrder2.clone());
        return clone;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.结果
    在这里插入图片描述

  • 相关阅读:
    【乐鑫 Demo】|ESP32-S3-BOX-3 惊喜开箱
    MySQL数据库修改字段编码
    【算法3.7】spfa(完结)
    Mysql语句的RegExp的用法与案例
    Github 2024-03-16 开源项目日报Top10
    OSMNX 路网数据下载分析Python包
    es6_数组新增的遍历方法
    7-14 整数拆分——递归/推
    《视觉SLAM十四讲》公式推导(二)
    CSS让两个标签在同一行显示并自适应宽度
  • 原文地址:https://blog.csdn.net/qq_42665745/article/details/128084262