原型模式怎样克隆对象 深拷贝与浅拷贝实现

原型模式通过复制对象创建新实例,浅拷贝复制引用地址,深拷贝递归复制所有引用对象,二者性能与隔离性权衡需根据实际需求选择。

原型模式怎样克隆对象 深拷贝与浅拷贝实现

原型模式是一种创建型设计模式,它的核心思想是通过复制已有对象来创建新对象,而不是通过 new 实例化。在 Java、JavaScript 等语言中,实现原型模式的关键在于对象的克隆,而克隆又分为浅拷贝深拷贝。下面详细说明如何实现这两种拷贝方式。

浅拷贝(Shallow Copy)

浅拷贝是指创建一个新对象,这个新对象会拥有原对象属性的副本,但属性如果是引用类型,复制的是引用地址,而不是引用对象本身。这意味着原对象和克隆对象会共享同一个引用对象。

以 Java 为例,实现浅拷贝需要:

类实现 Cloneable 接口 重写 Object 类中的 clone() 方法示例代码:

class Address {    String city;    Address(String city) {        this.city = city;    }}class Person implements Cloneable {    String name;    Address address;    Person(String name, Address address) {        this.name = name;        this.address = address;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

测试浅拷贝效果:

Address addr = new Address("Beijing");Person p1 = new Person("Alice", addr);Person p2 = (Person) p1.clone();// 修改 p1 的 address.cityp1.address.city = "Shanghai";System.out.println(p2.address.city); // 输出 Shanghai

可以看到,p2 的 address.city 也被改变了,因为 address 是引用类型,浅拷贝只复制了引用。

深拷贝(Deep Copy)

深拷贝会复制对象及其引用的所有对象,形成一个完全独立的副本。原对象和克隆对象之间没有任何关联。

实现深拷贝有几种常见方式:

1. 克隆引用对象(手动深拷贝)

在 clone() 方法中,对引用类型也手动调用 clone()。

@Overrideprotected Object clone() throws CloneNotSupportedException {    Person p = (Person) super.clone();    p.address = (Address) address.clone(); // 假设 Address 也实现了 Cloneable    return p;}

注意:Address 类也必须实现 Cloneable 并重写 clone()。

2. 序列化实现深拷贝

利用对象序列化和反序列化来实现真正的深拷贝,适用于复杂对象结构。

public Person deepCopy() throws IOException, ClassNotFoundException {    // 序列化    ByteArrayOutputStream bos = new ByteArrayOutputStream();    ObjectOutputStream oos = new ObjectOutputStream(bos);    oos.writeObject(this);    // 反序列化    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());    ObjectInputStream ois = new ObjectInputStream(bis);    return (Person) ois.readObject();}

前提是类和引用类型都实现 Serializable 接口。

3. 使用 JSON 工具(JavaScript 或 Java)

在 JavaScript 中常用 JSON.parse(JSON.stringify(obj)) 实现深拷贝(但有局限,如函数、undefined、Symbol 会丢失)。

const p1 = { name: "Alice", address: { city: "Beijing" } };const p2 = JSON.parse(JSON.stringify(p1));

在 Java 中也可使用 Gson、Jackson 等工具实现类似效果。

浅拷贝 vs 深拷贝对比

浅拷贝速度快,内存开销小,但存在共享引用的风险 深拷贝独立性强,安全,但性能开销大,尤其对复杂对象 选择哪种方式取决于业务需求:是否需要完全隔离对象状态

基本上就这些。原型模式中,根据对象结构选择合适的拷贝方式,能有效提升对象创建效率并避免副作用。关键是理解引用类型在拷贝过程中的行为差异。

以上就是原型模式怎样克隆对象 深拷贝与浅拷贝实现的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1472443.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月18日 19:37:27
下一篇 2025年12月9日 11:26:00

相关推荐

  • C++函数模板怎么定义 类型参数化实现方法

    C++函数模板通过template将类型参数化,使同一函数逻辑适用于多种类型,编译时根据实参类型推导并实例化具体函数版本,如add(5,3)生成int版本,add(3.14,2.71)生成double版本,实现代码复用;为解决通用逻辑不适用的特殊情况,可对特定类型全特化,如为const char*提…

    好文分享 2025年12月18日
    000
  • 联合体在系统编程中应用 硬件寄存器访问典型案例

    联合体在硬件寄存器访问中非常重要,1. 因为它允许以不同方式访问同一内存区域,既可通过位域精确控制寄存器的每一位,又能通过原始值整体读写;2. 使用联合体结合volatile关键字可确保对硬件寄存器的实时访问,避免编译器优化带来的问题;3. 联合体还适用于网络协议解析和数据类型底层转换等场景,但需注…

    2025年12月18日
    000
  • C++字面量操作符 自定义类型后缀

    C++自定义字面量操作符通过定义以_开头的后缀(如_m、_cm),将带单位的字面量直接转换为自定义类型对象,提升代码可读性与类型安全性。核心是实现operator””后缀函数,支持整数(unsigned long long)、浮点(long double)和字符串(const…

    2025年12月18日
    000
  • C++构造函数异常 对象构造失败处理

    构造函数抛出异常时,对象未完全构造,析构函数不会被调用,已构造的成员变量和基类按逆序自动析构,确保资源释放;应使用RAII(如智能指针)管理资源,避免泄漏;可通过函数try块捕获成员或基类异常并转换异常类型;设计上建议将可能失败的操作移至初始化函数,采用两段式构造,提升异常安全性。 当C++对象在构…

    2025年12月18日
    000
  • C++内存映射文件 大文件高效访问技术

    答案:内存映射文件通过将文件直接映射到进程地址空间,避免传统I/O的数据拷贝开销,适用于大文件处理、随机读写、多进程共享等场景;在C++中,Windows使用CreateFileMapping和MapViewOfFile,Linux使用mmap实现;需注意跨平台差异、页面错误、虚拟内存消耗及多线程/…

    2025年12月18日
    000
  • C++类如何定义 访问控制public private protected

    C++类通过class定义,public、private、protected控制成员访问权限:public成员可被外部访问,private仅类内访问,protected允许类内和子类访问。构造函数用于初始化对象,支持重载。示例中MyClass定义了三种访问级别的成员,DerivedClass继承My…

    2025年12月18日
    000
  • 怎样实现对象池模式 重复利用对象提高性能

    对象池模式通过复用对象减少创建和销毁开销,适用于数据库连接、线程等高成本对象;其核心是预先创建对象并放入池中,使用时获取、用后归还并重置状态,通过concurrentlinkedqueue实现线程安全的获取与归还机制,配合supplier提高通用性,且需注意池大小控制、空闲回收与对象泄漏问题,实际开…

    2025年12月18日
    000
  • 怎样配置C++的声学处理环境 JUCE音频框架集成

    答案是配置C++声学处理环境需正确集成JUCE框架与第三方库。首先通过Projucer或CMake创建项目并添加juce_audio_basics、juce_audio_devices、juce_dsp等模块,确保编译器和链接器正确配置头文件与库路径;使用target_include_directo…

    2025年12月18日
    000
  • 成员函数怎样定义 常成员函数与静态成员函数区别

    常成员函数用于保证不修改对象状态,可被const对象调用并访问非静态成员变量(只读),而静态成员函数不依赖对象实例,无this指针,只能访问静态成员,通过类名直接调用,两者不可同时定义为const static。 在C++中,成员函数是类的重要组成部分,用于操作类的数据成员或实现特定功能。根据使用场…

    2025年12月18日
    000
  • C++智能指针容器 vector存储shared_ptr

    使用vector存储shared_ptr可安全管理动态对象生命周期,避免内存泄漏。它通过引用计数自动释放内存,支持共享所有权,在扩容时安全复制,适用于需共享的对象集合,如游戏实体或GUI组件。需注意循环引用、性能开销及线程安全问题。 在C++中,使用 std::vector 存储 std::shar…

    2025年12月18日
    000
  • C++运算符重载规则 算术运算符重载示例

    C++中运算符重载允许为类类型定义算术运算行为,示例中Complex类通过成员函数重载+、-、*、/实现复数计算,遵循不改变优先级、使用const引用参数等规则,并通过友元函数重载 在C++中,运算符重载允许我们为自定义类型(如类或结构体)赋予标准运算符新的行为。算术运算符如 +、–、*…

    2025年12月18日
    000
  • C++数组查找元素 线性与二分查找实现

    线性查找适用于无序数组,时间复杂度O(n);二分查找效率高,时间复杂度O(log n),但要求数组有序。 在C++中查找数组中的元素,最常用的方法是线性查找和二分查找。它们各有适用场景:线性查找适用于无序数组,时间复杂度为O(n);二分查找效率更高,时间复杂度为O(log n),但要求数组必须有序。…

    2025年12月18日
    000
  • C++模板调试技巧 编译错误诊断方法

    掌握C++模板调试需理解编译器实例化过程与错误信息,通过简化问题、使用static_assert、类型推导工具、编译选项优化、IDE调试、SFINAE、CRTP、错误信息分析、代码隔离、测试框架及搜索引擎等方法提升效率。 模板调试,那可真是C++程序员的噩梦之一。 编译错误信息又臭又长,定位问题犹如…

    2025年12月18日
    000
  • C++this指针作用 当前对象引用使用场景

    this指针指向调用成员函数的当前对象,用于区分成员变量与参数、实现链式调用、防止自赋值及传递当前对象,是C++面向对象机制的核心组成部分。 this 指针是 C++ 中一个隐含的指针,它指向调用成员函数的当前对象实例。每个非静态成员函数都会自动接收到一个指向当前对象的 this 指针,它使得函数能…

    2025年12月18日
    000
  • C++虚假共享问题 缓存行填充解决方案

    虚假共享指多线程中独立变量因同属一个缓存行而引发频繁同步,降低性能;通过缓存行填充或alignas对齐使变量独占缓存行,可有效避免该问题。 在多线程C++程序中,即使变量是独立的,也可能因为它们在内存中靠得太近而引发性能问题。这种现象叫做“虚假共享”(False Sharing),它会显著降低程序的…

    2025年12月18日
    000
  • C++ deque容器原理 双端队列数据结构分析

    deque是分段连续存储的动态数组,支持两端高效插入删除和近似随机访问。它通过map管理多个缓冲区,避免了vector扩容时的全量复制,同时比list更利于缓存。与vector相比,deque在首尾增删更快,但不保证全局内存连续;与list相比,deque空间开销更小且支持随机访问。适用于需频繁在两…

    2025年12月18日
    000
  • 解释器模式怎么处理语法 特定领域语言实现

    解释器模式通过将语法规则映射为类,构建抽象语法树(AST)来解析和执行领域语言。每个节点实现interpret方法,递归解释表达式,适用于结构简单的DSL,如布尔条件”username=’admin’ AND loginCount>3″。通过上下…

    2025年12月18日
    000
  • 适配器容器怎么使用 stack和queue实现原理

    std::stack和std::queue是适配器容器,基于底层容器(如deque、vector、list)提供受限接口,分别实现LIFO和FIFO语义,默认使用deque因其两端高效操作且缓存性能好。 std::stack 和 std::queue 并非独立的容器,它们是所谓的“适配器容器”。其核…

    2025年12月18日
    000
  • C++ string类操作 常用字符串处理方法

    C++ string类提供构造、赋值、访问、查找、替换等丰富操作,通过实例演示了长度获取、子串提取、内容替换等功能,并推荐使用stringstream或reserve提升大量字符串拼接效率,同时介绍string::npos用于表示查找失败,以及stoi/to_string等函数实现字符串与数值转换。…

    2025年12月18日
    000
  • C++建造者模式实现 分步构建复杂对象

    建造者模式通过分离复杂对象的构建与表示,使同一构造过程可创建不同对象。包含Product(报告)、Builder(抽象构建接口)、ConcreteBuilder(如HtmlReportBuilder)和Director(指挥构建流程)。示例中用ReportDirector指导HtmlReportBu…

    2025年12月18日
    000

发表回复

登录后才能评论
关注微信