【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )(一)

简介: 【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )(一)

I . 原型模式 总结


1 . 原型模式本质及性能 : 原型模式使用 clone 方法克隆对象 , 其本质是在内存中拷贝二进制数据 , 这种方式要比调用 new 构造函数性能高得多 ;



2 . clone 核心是内存拷贝 : clone 对象不使用复用原有对象 , 是在内存中的另一个地址空间复制了一份一模一样的数据 , 然后将其首地址给新对象的引用 ;



3 . 原型模式适用场景 : ① 节省资源 ( 内存 CPU 硬件等 ) , ② 构造函数复杂 ( 计算繁琐 耗时 ) , ③ 创建大量对象 ;



4 . 原型模式实现 : 原型模式类实现 Cloneable 接口 , 实现其中的 clone 方法 ;



① 浅拷贝实现 : 浅拷贝默认调用 super.clone ;


② 深拷贝实现 : 深拷贝需要调用 每个引用成员对象的 clone 方法创建成员对象 , 然后赋值给新的原型模式创建的对象 , 作为其中的成员 ;



5 . 注意拷贝方式 : 默认浅拷贝 , 如果类中有引用类型成员变量 , 需要考虑深拷贝问题 , 可能会出现多个对象持有同一个引用变量 ;




II . 原型模式 浅拷贝


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



① 基础数据类型 : 如果类中全部是基础数据类型 , 使用 clone 可以将该类完整的复制一份 ;


② 引用数据类型 : 如果类中有引用类型成员 , 只是拷贝该成员的地址 , 所有的拷贝创建的原型模式实例对象都持有同一个引用 , 如果修改该引用成员的值 , 所有的原型对象实例的值都会跟着修改 ;



2 . 浅拷贝示例 :



① 原型模式类 Student : 该类中持有 Vector<String> courses 引用数据类型 , 调用 clone 方法在内存中复制对象时 , 仅复制了对象的地址 , 即将该引用的地址赋值给了 clone 出的对象 ;


package kim.hsl.design.prototype.shallowcopy;
import java.util.Vector;
/**
 * 浅拷贝示例
 */
public class Student implements Cloneable {
    private String name;
    private int age;
    //该类在拷贝时 , 如果使用浅拷贝 , 只是将地址拷贝走了 , 两个对象实际上用的是同一个对象
    private Vector<String> courses = new Vector<>();
    public Student() {
        System.out.println("调用 Student 默认构造函数");
    }
    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 Vector<String> getCourses() {
        return courses;
    }
    public void setCourses(Vector<String> courses) {
        this.courses = courses;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", courses=" + courses +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("调用 Student clone 方法");
        return super.clone();
    }
}




② 测试类 Main : 此处创建了两个 Student 实例对象 , 但是两个对象都持有同一个 Vector<String> courses 引用数据类型成员 , 当修改其中一个成员时 , 两个对象中的该成员都会改变 ;


package kim.hsl.design.prototype.shallowcopy;
public class Main {
    public static void main(String[] args) {
        try {
            //测试使用 clone 方法实现的原型模式 , 使用原型模式创建 2 个对象
            Student newStudent = new Student();
            // 1 . 使用 clone 方法创建对象1
            Student student = (Student) newStudent.clone();
            student.setName("Tom");
            student.setAge(10);
            student.getCourses().add("数学");
            // 2 . 使用 clone 方法创建对象2
            Student student2 = (Student) newStudent.clone();
            student2.setName("Jerry");
            student2.setAge(18);
            student2.getCourses().add("语文");
            System.out.println("student : " + student + "\nstudent2 : " + student2);
        } catch (CloneNotSupportedException e) {
            //捕获 clone 方法可能产生的异常
            e.printStackTrace();
        }
    }
}



③ 执行结果 : 调用第一个对象 add 方法 , 在 vector 集合中添加了 “数学” 字符串 , 调用第二个对象的 add 方法 , 向 courses 集合中添加 “语文” 字符串 , 理论上两个分别是 “数学” 和 “语文” , 但是此处却都变成了 “数学” “语文” 两个课程 , 说明两个原型模式对象持有的 Vector<String> courses 变量是指向同一个内存地址的 ;


调用 Student 默认构造函数
调用 Student clone 方法
调用 Student clone 方法
student : Student{name='Tom', age=10, courses=[数学, 语文]}
student2 : Student{name='Jerry', age=18, courses=[数学, 语文]}



III . 原型模式 深拷贝


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



2 . 深拷贝 clone 方法流程 :



① 创建实例对象 : 通过 clone 方法 , 创建原型模式类的实例对象 , 此时该对象的引用成员处于浅拷贝状态 ;


② 拷贝引用成员 : 调用原型模式类对象成员的 clone 对象 , 创建新的成员对象 , 将新的成员对象赋值给克隆出的原型模式对象 ;


③ 返回新的对象 : 返回 clone 创建的原型模式实例对象 ;



目录
相关文章
|
2月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
40 2
|
4月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
|
4月前
|
设计模式 存储 安全
设计模式——设计模式介绍和单例设计模式
饿汉式(静态常量)、饿汉式(静态代码块)、懒汉式(线程不安全)、懒汉式(线程安全,同步方法)、懒汉式(线程不安全,同步代码块)、双重检查(推荐,线程安全、懒加载)、静态内部类(推荐)、枚举(推荐)
|
4月前
|
设计模式 Java
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
|
5月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
70 1
|
6月前
|
设计模式
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
|
5月前
|
设计模式 Java
【Java】单例设计模式
【Java】单例设计模式
|
6月前
|
设计模式 JavaScript
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
61 6
|
6天前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式