【设计模式-原型】

**原型模式(Prototype Pattern)**是一种创建型设计模式,旨在通过复制现有对象的方式来创建新对象,而不是通过实例化类来创建对象。该模式允许对象通过克隆(复制)来创建新的实例,因此避免了重新创建对象带来的开销,尤其在对象创建复杂、耗时的情况下。

1. 定义

原型模式使用一个现有的对象作为原型,创建新对象时,通过克隆该对象来生成新对象。这个模式提供了一个接口来复制已有对象,并允许客户端通过该接口请求复制对象。

2. 原型模式的结构

原型模式主要包含以下几个部分:

  • Prototype(原型接口):定义了一个 clone() 方法,用于克隆自身。具体实现可以是浅拷贝或深拷贝。
  • ConcretePrototype(具体原型类):实现了 Prototype 接口,并实现 clone() 方法。通常使用 Java 的 Cloneable 接口来实现克隆。
  • Client(客户端):通过调用原型的 clone() 方法来获取对象,而不是直接通过构造函数创建对象。

3. 原型模式的工作原理

原型模式的关键在于提供一个能够复制自身的原型接口,并在具体类中实现该接口的 clone() 方法。通过克隆现有对象来创建新对象,这样既节省了资源,又能提高系统性能。

3.1 浅拷贝 vs 深拷贝
  • 浅拷贝:复制对象时,拷贝所有字段,但如果字段是对象类型,则只复制对象的引用。换句话说,浅拷贝只是复制了对象的内存地址,因此新旧对象共享相同的引用类型字段。
  • 深拷贝:不仅复制字段,还会递归地复制引用类型的对象,确保新对象是独立的,彼此不共享任何状态。

4. 原型模式的 UML 类图

在这里插入图片描述

5. Java 中的原型模式示例

Java 提供了 Cloneable 接口和 Object 类中的 clone() 方法,支持原型模式的实现。

5.1 示例代码
class Prototype implements Cloneable {
    private String name;
    private int age;
    
    public Prototype(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 实现 clone 方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 浅拷贝
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Prototype{name='" + name + "', age=" + age + "}";
    }
}

public class PrototypePatternDemo {
    public static void main(String[] args) {
        try {
            // 创建原型对象
            Prototype original = new Prototype("Alice", 25);
            System.out.println("Original Object: " + original);

            // 克隆原型对象
            Prototype clone = (Prototype) original.clone();
            System.out.println("Cloned Object: " + clone);

            // 修改原始对象,会影响克隆对象
            System.out.println("Objects are different: " + (original != clone));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出:

Original Object: Prototype{name='Alice', age=25}
Cloned Object: Prototype{name='Alice', age=25}
Objects are different: true
5.2 深拷贝示例
class Address implements Cloneable {
    private String city;
    private String country;

    public Address(String city, String country) {
        this.city = city;
        this.country = country;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 浅拷贝
    }

    @Override
    public String toString() {
        return "Address{city='" + city + "', country='" + country + "'}";
    }
}

class Person implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深拷贝: 克隆引用类型字段
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone();  // 深拷贝 Address 对象
        return cloned;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", address=" + address + "}";
    }
}

public class DeepCopyDemo {
    public static void main(String[] args) {
        try {
            // 创建原型对象
            Address address = new Address("New York", "USA");
            Person person1 = new Person("John", 30, address);
            System.out.println("Original: " + person1);

            // 克隆对象
            Person person2 = (Person) person1.clone();
            System.out.println("Cloned: " + person2);

            // 修改原始对象中的地址,不影响克隆对象中的地址
            address.city = "Los Angeles";
            System.out.println("After modifying address:");
            System.out.println("Original: " + person1);
            System.out.println("Cloned: " + person2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出:

Original: Person{name='John', age=30, address=Address{city='New York', country='USA'}}
Cloned: Person{name='John', age=30, address=Address{city='New York', country='USA'}}
After modifying address:
Original: Person{name='John', age=30, address=Address{city='Los Angeles', country='USA'}}
Cloned: Person{name='John', age=30, address=Address{city='New York', country='USA'}}

6. 原型模式的优点

  • 性能优化:当创建对象代价较高时,克隆可以比通过构造函数创建新对象更加高效。
  • 动态创建对象:原型模式允许在运行时动态地创建对象,而不需要知道具体的类或实现。
  • 减少子类数目:避免了频繁的使用子类去生成对象,通过克隆可以生成对象的不同版本。

7. 原型模式的缺点

  • 深拷贝复杂:如果对象中有复杂的嵌套对象或循环引用,深拷贝的实现会非常复杂,需要逐层克隆每个引用的对象。
  • 依赖于具体的实现:克隆对象需要依赖类的 clone() 方法,可能会限制类的灵活性。

8. 原型模式的应用场景

  • 资源消耗大的对象创建:比如对象创建需要读取数据库、大量计算或需要访问网络资源时,可以使用原型模式进行克隆操作。
  • 重复创建相似对象:在某些系统中,需要频繁创建内容相似的对象,使用原型模式可以节省时间。
  • 不可变对象的场景:某些情况下,创建后不可修改的对象,原型模式可以保证对象的唯一性和一致性。

9. 总结

原型模式是一种有效的设计模式,适用于创建开销较大的对象。通过 clone() 方法,可以快速创建相同或类似的对象,减少创建新对象的成本。同时,它支持浅拷贝和深拷贝的灵活实现,在复杂的对象克隆场景下,深拷贝需要特别的设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899108.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git核心概念图例与最常用内容操作(reset、diff、restore、stash、reflog、cherry-pick)

文章目录 简介前置概念.git目录objects目录refs目录HEAD文件 resetreflog 与 reset --hardrevert(撤销指定提交)stashdiff工作区与暂存区差异暂存区与HEAD差异工作区与HEAD差异其他比较 restore、checkout(代码撤回)merge、rebase、cherry-pick 简介 本文将介绍Git几个核心概念…

赛氪提供专业技术支持,首届“天翼云息壤杯”高校AI大赛正式开启

2024年9月25日,在ICT中国2024高层论坛暨国际信息通信展主论坛上,首届“天翼云息壤杯”高校AI大赛正式拉开帷幕。中国电信总经理梁宝俊出席并发表了致辞。此次大赛由国务院国资委、工业和信息化部、教育部等部委指导,中国电信集团有限公司和华…

【排序】快排思想以及例子

思想 使用分治法来处理数据 例题 19 97 09 17 01 08 首先确定一个pivot 一般是首位&#xff0c;把比p小的放p的左边&#xff0c;比p大的放p的右边。L是左指 R是右指 首轮排序 p 19 __ 97 09 17 01 08 L R 首先应从R开始判断 08<19 08替换到p所在位置&#xff0c;R移动 p 19…

【AIGC】AI时代降临,AI文案写作、AI绘画、AI数据处理

目录 1、ChatGPTAI文案与写作108招2、AI短视频生成与剪辑实战108招3、AI绘画与摄影实战108招4、AI商业广告设计实战108招5、AI数据处理实战108招6、AI智能办公实战108招 传送门&#xff1a;清华大学出版社AI实战108招 全6册 1、ChatGPTAI文案与写作108招 《ChatGPTAI文案与写…

DDD重构-实体与限界上下文重构

DDD重构-实体与限界上下文重构 概述 DDD 方法需要不同类型的类元素&#xff0c;例如实体或值对象&#xff0c;并且几乎所有这些类元素都可以看作是常规的 Java 类。它们的总体结构是 Name: 类的唯一名称 Properties&#xff1a;属性 Methods: 控制变量的变化和添加行为 一…

MySQL 基础查询

1、DISTINCT select DISTINCT EMPLOYEE_ID ,FIRST_NAME from employees 按照ID去重&#xff0c;DISTINCT的字段要放在前面&#xff0c;不会再继续在FIRST_NAME上去重判断&#xff1b; 如果需要多字段去重&#xff0c;需要用到group by&#xff0c;这个后面讲&#xff1b; …

Redis-04 Redis管道

Redis 管道&#xff08;Pipelining&#xff09;是一种技术&#xff0c;它允许客户端一次发送多个命令给服务器&#xff0c;而无需等待每个命令的响应。这样可以减少网络延迟和提高命令的执行效率。 创建txt文件&#xff0c;里面写需要执行的操作&#xff0c;然后使用cat命令一次…

【C++打怪之路Lv11】-- stack、queue和优先级队列

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…

基于SSM+微信小程序的家庭记账本管理系统(家庭1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 1、管理员端功能有首页、个人中心、用户管理&#xff0c;消费详情管理、收入详情管理、系统管理等。 2、用户端功能有首页、消费详情、收入详情、论坛信息、我的等功能。 2、项目技术 …

C语言教程——数组(1)

目录 系列文章目录 前言 1、一维数组的创建和初始化 1.1数组的创建 1.2数组的初始化 1.3一维数组的使用 总结 1.4一维数组在内存中的存储 2、二维数组的创建和初始化 2.1二维数组的创建 2.2二维数组的初始化 2.3二维数组的使用 2.4二维数组在内存中的存储 3、数组…

时空智友企业流程化管控系统uploadStudioFile接口存在任意文件上传漏洞

免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. 时空智友…

【Vulnhub靶场】Kioptrix Level 3

目标 本机IP&#xff1a;192.168.118.128 目标IP&#xff1a;192.168.118.0/24 信息收集 常规 nmap 扫存活主机&#xff0c;扫端口 根据靶机IP容易得出靶机IP为 192.168.118.133 nmap -sP 192.168.118.0/24nmap -p- 192.168.118.133 Getshell 开放22端口和80 端口 访问web…

C++进阶之路:日期类的实现、const成员(类与对象_中篇)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

如何选择合适的云服务商,看IDC怎么说

01 | 2份IDC报告&#xff0c;评估了Covid后的云增长与云服务市场的变化 《IDC MarketScape&#xff1a;全球公有云基础设施即服务提供商评估》&#xff08;2022&#xff09;共评估了 13 家云提供商&#xff0c;其中既有超大规模云服务商&#xff0c;如亚马逊云科技&#xff1b…

论文阅读-三维结构几何修复(导-4)

摘要 解决了3D数字模型中大洞修复的问题。 通过基于字典学习的方法解决了缺失区域推断问题&#xff0c;该方法利用从单个自相似结构和在线深度数据库中得出的几何先验。利用几何先验提供的线索&#xff0c;从洞的边界周围自适应地传播局部3D表面平滑性来恢复底层表面。在合成…

word中的内容旋转90度

在vsto、Aspose.Words 中&#xff0c;默认没有直接的 API 可以让表格整体旋转 90 度。然而&#xff0c;我们可以通过一些方式来实现类似的效果&#xff0c;具体思路如下&#xff1a; 将表格插入到一个形状&#xff08;Shape&#xff09;或文本框中&#xff0c;然后旋转该形状。…

使用Docker启动的Redis容器使用的配置文件路径等问题以及Python使用clickhouse_driver操作clickhouse数据库

一、使用Docker启动的Redis容器使用的配置文件路径等问题 1.docker启动的redis使用的配置文件路径是什么 使用docker搭建redis服务&#xff0c;本身redis启动的时候可以指定配置文件的&#xff0c; redis-server /指定配置文件路径/redis.conf。 但手上也没有一个redis配置文件…

【Golang】合理运用泛型,简化开发流程

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

灵动AI视频最新AIGC 系统:支持多种模型切换 支持5端部署

灵动AI视频官网地址&#xff1a;https://aigc.genceai.com/

SeCo复现

表1 复现结果–CAM&#xff1a;74.751 Mask&#xff1a;76.47 Val&#xff1a;74.0 Test&#xff1a;73.7948&#xff0c;完全一致 表3 复现结果&#xff1a;0.233&#xff0c;完全一致 感想 第10篇完全复现的论文