• 「设计模式」原型模式


    「设计模式」原型模式

    引言

    在开发过程中,有时会遇到为一个类创建多个实例的情况,这些实例内部成员往往完全相同或有细微的差异,而且实例的创建开销比较大或者需要输入较多参数,如果能通过复制一个已创建的对象实例来重复创建多个相同的对象,这就可以大大减少创建对象的开销,这个时候就需要原型模式。


    一、概述

    原型模式: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

    使用场景:

    • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。

    • 性能和安全要求比较高。

    二、主要角色

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

    三、浅拷贝

    浅拷贝: 对于基本数据类型,会直接复制值给拷贝对象;对于引用数据类型,只拷贝对象地址,指向原来对象的地址。

    // 基本类型浅拷贝:
    int a = 100;
    int b = a;
    System.out.println(a); // 100
    System.out.println(b); // 100
    System.out.println(a==b); // true
    
    // 引用数据类型浅拷贝:
    // 定义学生类
    class Student{
            private String name;
            int age;
    
            public Student(String name, int age) {
                    this.name = name;
                    this.age = age;
            }
    
            public String getName() {
                    return name;
            }
    
            public void setName(String name) {
                    this.name = name;
            }
    
            public int getAge() {
                    return age;
            }
    
            public void setAge(int age) {
                    this.age = age;
            }
    }
    
    
    //测试
    
    Student student1 = new Student("stu",18);
    System.out.println(student1); // JavaPackage_1.Student@68b0af6
    
    Student student2 = student1;
    System.out.println(student2); // JavaPackage_1.Student@68b0af6
    System.out.println(student1==student2); // true,student1和student2指向的是同一地址
    
    student1.setName("newstu");
    System.out.println(student2.getName()); // newstu,通过修改student1可以修改student2
    
    • 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

    四、深拷贝

    深拷贝: 无论基本类型还是引用类型,全部拷贝为一个新的对象,属性中引用的其他对象也会被拷贝,不指向原有对象的地址。


    五、原型模式实现

    • 在Java的Cloneable接口中提供的拷贝机制。
    • Java中的Object类中提供了clone()方法来实现浅拷贝。
    • 虽然对象成功拷贝,但是其内层对象并没有进行拷贝,依然只是对象引用的复制。
    // 定义Food类
    class Food{
    
            String food;
    
            public String getFood() {
                    return food;
            }
    
            public void setFood(String food) {
                    this.food = food;
            }
    
            public Food(String food) {
                    this.food = food;
            }
    }
    
    // 定义Student类
    class Student implements Cloneable{ // Cloneable接口
    
            @Override //重写clone()方法
            // 提升访问权限为public
            public Object clone() throws CloneNotSupportedException {
                    return super.clone();
            }
    
            private Food food;
            private String name;
            int age;
    
            public Student() {
            }
    
            public Student(String name, int age, Food food) {
                    this.name = name;
                    this.age = age;
                    this.food = food;
            }
    
            public String getName() {
                    return name;
            }
    
            public void setName(String name) {
                    this.name = name;
            }
    
            public int getAge() {
                    return age;
            }
    
            public void setAge(int age) {
                    this.age = age;
            }
    
            public void setFood(Food food){
                    this.food = food;
            }
    
            public Food getFood(){
                    return food;
            }
    
    }
    
    • 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
    • 62
    • 63
    • 64
    • 65

    //测试
    
    Student student1 = new Student("stu", 29,food);
    Student student2 = (Student) student1.clone(); // 通过student1克隆student2,不通过new对象的形式创建
    
    System.out.println(student1); // JavaPackage_1.Student@682a0b20
    System.out.println(student2); // JavaPackage_1.Student@3d075dc0
    System.out.println(student1==student2); // false,student1和student2指向的是不同地址
    
    System.out.println(student1.getFood()); // JavaPackage_1.Food@58b835a
    System.out.println(student2.getFood()); // JavaPackage_1.Food@58b835a
    System.out.println(student1.getFood()==student2.getFood()); // true,student1.food和student2.food指向同一地址
    
    food.setFood("orange");
    System.out.println(student1.getFood().getFood()); // orange
    System.out.println(student2.getFood().getFood()); // orange
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这样,使用了clone()方法实现了浅拷贝,由测试结果知道,对象student1和student2中的food仍是指向的同一地址。下面,对上述代码进行改进,实现原型模式的深拷贝

    六、原型模式改进

    image-20221106014049498

    下面,通过修改clone()方法实现深拷贝:
    @Override
    public Object clone() throws CloneNotSupportedException { // 提升访问权限
            Student student = (Student) super.clone();
            //针对成员变量进行拷贝
            student.name = new String(name);
            student.food = new Food(food.getFood());
            return student;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    //测试
    
    Food food  = new Food("apple");
    System.out.println(food); // JavaPackage_1.Food@6d311334
    
    //Java深拷贝,对内层的对象也进行拷贝。
    Student student1 = new Student("stu", 29,food);
    // 通过student1克隆student2,不通过new对象的形式创建
    Student student2 = (Student) student1.clone(); 
    
    System.out.println(student1); // JavaPackage_1.Student@3d075dc0
    System.out.println(student2); // JavaPackage_1.Student@214c265e
    System.out.println(student1==student2); // false,student1和student2指向的是不同地址
    
    System.out.println(student1.getFood()); // JavaPackage_1.Food@6d311334
    System.out.println(student2.getFood()); // JavaPackage_1.Food@448139f0
    System.out.println(student1.getFood()==student2.getFood()); // false,student1.food和student2.food指向不同地址
    
    food.setFood("orange");
    System.out.println(student1.getFood().getFood()); // orange
    System.out.println(student2.getFood().getFood()); // apple
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    image-20221106014852021

    七、总结

    原型模式没有复杂的继承体系,只需要使需要具有拷贝功能的类实现Cloneable接口并重写clone()方法即可。但它的应用却及其广泛,它将对一个对象中各个字段(不管是私有的还是共有的)的复制操作封装在了clone()方法中,这样,使用该类的用户就不需要对对象中的各个字段的细节进行了解,直接调用clone()方法就可以实现对象的拷贝,而且,通过clone()方法还可以为不同的字段设置被复制的权限,从而允许仅对可以被复制的字段进行复制。

    参考:

    Java设计模式(五) 原型模式详解

    Java设计模式之原型模式

  • 相关阅读:
    138.深度学习分布式计算框架-1
    华为智慧屏,吹尽狂沙始到金
    基于Hadoop的网上购物行为分析设计与实现
    第11章 SwaggerUI企业服务文档构建
    [NLP] Llama2模型运行在Mac机器
    怎么申请工程勘察资质,申请工程勘察乙级资质需要满足什么条件
    ENVI:如何进行图像融合?
    echarts、dataV 数据可视化大屏
    OneFlow源码解析:自动微分机制
    Websocket升级版
  • 原文地址:https://blog.csdn.net/u014571143/article/details/127711801