设计模式-3.3原型模式


📝 原型模式


🟢 概述

  • 📌 原型模式的核心思想是通过复制现有对象来创建新的对象,而不是通过实例化的方式。
  • 📌 这种模式特别适用于对象的创建成本较高、复杂或者系统需要保护某些对象的信息而使其不被修改时。

🟢 特点

  • 📌 性能和资源: 可以解决构建复杂对象的资源消耗问题,能在某些场景中提升构建对象的效率。
  • 📌 保护性拷贝: 返回一个拷贝对象,实现只读的限制。

🟢 结构

  • 抽象原型类:

    • 📌 定义了一个 clone 接口,规定了具体原型对象必须实现的方法。
    • ⚠️ 注意: 在Java中,可以通过实现 Cloneable 接口并重写 clone 方法来达到这一要求。
  • 具体原型类:

    • 📌 实现或继承抽象原型类,并重写 clone 方法。
    • 📌 该类的对象是可被复制的。
  • 对象访问类:

    • 📌 使用具体原型类中的 clone 方法来复制新的对象。

⚠️ 注意: 使用原型模式时要处理深拷贝和浅拷贝的问题。浅拷贝只复制对象的基本类型,对象类型仍然指向原来的地址。深拷贝则会复制对象内的所有属性,包括对象。


📝 深克隆和浅克隆


📌 浅克隆 (Shallow Clone)


🟢 特点

  • 基本数据类型:

    • 📌 在浅克隆中,当对象被复制后,所有基本数据类型(如 int, float, char 等)的变量都会重新创建。
  • 引用类型:

    • 📌 对于引用类型(如数组、对象引用等),浅克隆只复制引用,不复制引用指向的对象。因此,原对象及其复制体中的这些引用类型变量仍然指向相同的对象。

🟢 例子

假设有一个对象 A,该对象有一个基本数据类型的变量 x 和一个引用类型的变量 y(指向对象 B)。

当对 A 进行浅克隆后:

  • 新对象 A'x 是新创建的,与原对象 A 中的 x 不共享存储空间。
  • 新对象 A'y 仍然指向对象 B,与原对象 A 中的 y 指向的是同一个对象 B

🟢 实现方式

  • 使用 clone 方法:

    • 📌 Java提供的默认 clone 方法就是浅克隆。
    • 📌 基本数据类型会被克隆,而引用类型的变量则只是复制了引用。
  • 使用工具类:

    • 📌 如 BeanUtil.copyProperties 可以进行浅克隆,但要确保不进行深度复制。
    • ⚠️ 注意: 需要留意该方法的具体行为和配置。

⚠️ 注意: 浅克隆可能会导致意外的问题,特别是当你希望复制的对象与原对象是完全独立的时候。在这种情况下,可能需要使用深克隆。


package com.study.notes.design.patterns.pattern.create.prototype.test3;

import java.io.Serializable;

/**
 * @version v1.0
 * @ClassName: Student
 * @Description: TODO(一句话描述该类的功能)
 * @Author: lzq
 */
public class Student implements Serializable {

    //学生的姓名
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

package com.study.notes.design.patterns.pattern.create.prototype.test3;

import java.io.Serializable;

/**
 * @version v1.0
 * @ClassName: Citation
 * @Description: TODO(一句话描述该类的功能)
 * @Author: lzq
 */
public class Citation implements Cloneable, Serializable {

    private Student stu;

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

    public void show() {
        System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

package com.study.notes.design.patterns.pattern.create.prototype.test2;

/**
 * @version v1.0
 * @ClassName: CitaionTest
 * @Description: TODO(一句话描述该类的功能)
 * @Author: lzq
 */
public class CitaionTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //1,创建原型对象
        Citation citation = new Citation();
        //创建张三学生对象
        Student stu = new Student();
        stu.setName("张三");
        citation.setStu(stu);

        //2,克隆奖状对象
        Citation citation1 = citation.clone();
        Student stu1 = citation1.getStu();
        stu1.setName("李四");

        //3,调用show方法展示
        citation.show();
        citation1.show();
    }
}


📌 深克隆 (Deep Clone)


🟢 特点

  • 基本数据类型:

    • 📌 在深克隆中, 所有基本数据类型(如 int, float, char 等)的变量都会重新创建。
  • 引用类型:

    • 📌 对于引用类型(如数组、对象引用等),深克隆会复制引用及引用指向的所有对象,直到该对象可达的所有对象。这意味着复制出的对象与原对象是完全独立的,它们不共享任何引用类型的成员变量。

🟢 例子

假设有一个对象 A,该对象有一个基本数据类型的变量 x 和一个引用类型的变量 y(指向对象 B)。

当对 A 进行深克隆后:

  • 新对象 A'x 是新创建的,与原对象 A 中的 x 不共享存储空间。
  • 新对象 A'y 指向一个新的对象 B',这个对象 B' 是对象 B 的深克隆。B'B 是完全独立的。

🟢 实现

  • 使用 clone 方法:

    • 📌 可以实现深克隆,但需要确保所有的成员变量都被正确克隆。
    • ⚠️ 注意: 需要递归地对所有引用类型的成员变量进行克隆。
  • 使用工具类:

    • 📌 如 BeanUtil.copyProperties 可以进行深克隆。
    • ⚠️ 注意: 该方法的限制和要求,以及是否真正满足深克隆的需求。
  • 序列化与反序列化:

    • 📌 通过对象的序列化和随后的反序列化来实现深克隆。
    • 📌 这种方法的好处是不需要为每个类编写复杂的克隆逻辑。

⚠️ 注意: 深克隆可能相对耗时和耗资源。只有当确实需要对象与其克隆体之间完全隔离时,才应该使用深克隆。


package com.study.notes.design.patterns.pattern.create.prototype.test3;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @version v1.0
 * @ClassName: CitaionTest
 * @Description: TODO(一句话描述该类的功能)
 * @Author: lzq
 */
public class CitaionTest {
    public static void main(String[] args) throws Exception {
        //1,创建原型对象
        Citation citation = new Citation();
        //创建张三学生对象
        Student stu = new Student();
        stu.setName("张三");
        citation.setStu(stu);

        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/robin/a.txt"));
        //写对象
        oos.writeObject(citation);
        //释放资源
        oos.close();

        //创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/robin/a.txt"));
        //读取对象
        Citation citation1 = (Citation) ois.readObject();
        //释放资源
        ois.close();
        Student stu1 = citation1.getStu();
        stu1.setName("李四");

        citation.show();
        citation1.show();
    }
}


⚠️ 注意: 无论是浅克隆还是深克隆,都需要确保对象的 clone 方法已被正确覆盖,并且该对象实现了 Cloneable 接口。否则,调用 clone 方法时会抛出 CloneNotSupportedException 异常。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yueerba126

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值