技术成神之路:设计模式(三)原型模式

1. 定义


原型模式(Prototype Pattern)是一种创建型设计模式,旨在通过复制现有对象来创建新对象,而不是通过实例化类的方式。这个模式可以提高对象创建的效率,尤其是在创建对象的过程非常复杂或代价高昂时。

2. 结构


原型模式包含以下角色:

  • Prototype(原型接口):用于声明克隆自身的方法。通常这个接口会定义一个名为clone的抽象方法。
  • ConcretePrototype(具体原型类):实现原型接口,并实现克隆自身的方法。这类对象可以被克隆。
  • Client(客户端):使用原型接口来克隆新的对象。

UML类图:
在这里插入图片描述

3. 示例代码


// 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型类A
class ConcretePrototypeA implements Prototype {
    private String name;

    public ConcretePrototypeA(String name) {
        this.name = name;
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototypeA{name='" + name + "'} hashcode= "+ hashCode();
    }
}

// 具体原型类B
class ConcretePrototypeB implements Prototype {
    private int value;

    public ConcretePrototypeB(int value) {
        this.value = value;
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototypeB{value=" + value + "} hashcode= "+ hashCode();
    }
}

测试:

@Test
    public void test() {
        ConcretePrototypeA prototypeA = new ConcretePrototypeA("Prototype A");
        ConcretePrototypeB prototypeB = new ConcretePrototypeB(42);

        Prototype clonedPrototypeA = prototypeA.clone();
        Prototype clonedPrototypeB = prototypeB.clone();

        System.out.println("原型A: "+prototypeA);
        System.out.println("克隆A: "+clonedPrototypeA);
        System.out.println("原型B: "+prototypeB);
        System.out.println("克隆B: "+clonedPrototypeB);
    }

打印:

原型A: ConcretePrototypeA{name='Prototype A'} hashcode= 1823541245
克隆A: ConcretePrototypeA{name='Prototype A'} hashcode= 1020154737
原型B: ConcretePrototypeB{value=42} hashcode= 398457879
克隆B: ConcretePrototypeB{value=42} hashcode= 1850954068

4. 应用场景


  • 对象的创建开销很大:通过克隆现有对象而不是重新创建,可以节省时间和资源。
  • 系统需要大量类似对象:通过克隆原型对象,可以快速生成多个相似但独立的对象。
  • 对象的状态需要动态改变:通过克隆原型对象,可以创建具有特定状态的新对象。

情景回顾:

原型模式在实际应用中可能并不常见,或许你见到过但没留意,因为它的应用场景太少了,让我想起了在写一个多任务下载模块时,每下载一个文件其都有对应的mode,记录一些下载信息状态信息等内容,再进行更新进度的时候需要把这个对象发送出去,通知外界更新UI,有一个问题就是下载中操作的对象和发送出去的对象是同一个,就会出现异常现象,我发送出去的下载进度是90%,UI还没来得及更新,这边又将进度修改为95%了,emm… 可能我描述的问题,你觉的不严重,但这种不可预测的现象是我们不希望发生的。
其中解决方式一 就是克隆一个对象,让UI显示的和下载操作的对象互不干扰,这时如果你new一个新对象的话相比克隆就劣势就凸显出来了。

5. 优缺点


优点:

  • 提高对象创建效率:避免了复杂对象的重复创建,通过克隆现有对象来生成新对象。
  • 动态创建对象:可以在运行时动态创建对象,而无需了解具体的类。
  • 减少子类的数量:通过克隆原型对象,可以减少创建子类的数量,增强系统的灵活性。

缺点:

  • 深拷贝和浅拷贝问题:在涉及复杂对象时,深拷贝和浅拷贝的问题需要特别注意。如果对象包含对其他对象的引用,浅拷贝可能不够用,需要实现深拷贝。
  • 克隆方法的实现复杂:对于一些复杂的对象,克隆方法的实现可能比较复杂,需要处理对象间的依赖关系。

6. 深拷贝与浅拷贝


在原型模式中,克隆可以分为浅拷贝和深拷贝:

  • 浅拷贝:复制对象时,只复制对象本身,而不复制对象所引用的其他对象。也就是说,复制后的对象与原对象共享对其他对象的引用。
  • 深拷贝:复制对象时,不仅复制对象本身,还复制对象所引用的其他对象。这样,复制后的对象与原对象是完全独立的,不共享任何引用。

7. 深拷贝与浅拷贝示例


// 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型类
class ConcretePrototype implements Prototype {
    private String name;
    private List<String> list;

    public ConcretePrototype(String name) {
        this.name = name;
        this.list = new ArrayList<>();
    }

    public void addToList(String item) {
        list.add(item);
    }

    public List<String> getList() {
        return list;
    }

    @Override
    public Prototype clone() {
        try {
            ConcretePrototype copy = (ConcretePrototype) super.clone();
            // 深拷贝 -测试浅拷贝时注释下面代码!!!
            copy.list = new ArrayList<>(this.list);
            return copy;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototype{name='" + name + "', list=" + list + "} list hashcode=" + list.hashCode();
    }
}

测试:

    @Test
    public void test() {
        ConcretePrototype prototype = new ConcretePrototype("Prototype");
        prototype.addToList("Item1");
        prototype.addToList("Item2");

        // 浅拷贝示例
        ConcretePrototype shallowClone = (ConcretePrototype) prototype.clone();

        // 添加新项到原型对象的列表
        prototype.addToList("Item3");

        System.out.println("原型: " + prototype);
        System.out.println("浅拷贝: " + shallowClone);

        // 深拷贝示例
        ConcretePrototype deepClone = (ConcretePrototype) prototype.clone();

        // 添加新项到深拷贝对象的列表
        deepClone.addToList("Item4");

        System.out.println("原型: " + prototype);
        System.out.println("深拷贝: " + deepClone);
    }

测试浅拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
浅拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142

可以看出两个对象所引用的list对象为同一个

测试深拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
深拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3, Item4]} list hashcode=-1296039165

两个对象引用的list完全不一样了,操作互不影响

8. 设计模式的比较


原型模式与其他创建型设计模式(如工厂模式、抽象工厂模式、单例模式等)有其独特之处:

  • 与工厂模式的区别:工厂模式通过提供一个方法来创建对象,而原型模式通过复制现有对象来创建新的对象。工厂模式适合对象创建过程简单但需要解耦对象创建过程的场景,而原型模式适合对象创建过程复杂且需要高效创建对象的场景。
  • 与单例模式的区别:单例模式确保一个类只有一个实例,而原型模式则允许通过克隆来创建多个实例。它们解决的问题不同,前者关注的是实例的唯一性,后者关注的是高效创建对象。

9. 结论


原型模式是一种高效的对象创建模式,它通过克隆现有对象来创建新对象,避免了通过构造函数创建对象的高昂代价,尽管原型模式在许多方面具有优势,但在实现过程中需要注意对象间的引用关系,确保深拷贝和浅拷贝的正确实现,以避免不必要的资源浪费和潜在的错误。

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

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

相关文章

创建线程的五种方式

一.继承Thread ,重写run class MyThread extends Thread{Overridepublic void run() {//这里的内容就是该线程要完成的工作while(true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeExceptio…

亚马逊跟卖卖家还在选品发愁吗!已经有卖家用这种方式选品大卖!

对于亚马逊相信很多卖家都不陌生&#xff0c;也有很多新手卖家涌入&#xff0c;但是进入后就不知道怎么选品了&#xff0c;很多新手卖家是不是天天盯着亚马逊页面的产品&#xff0c;眼花撩乱的&#xff0c;不知道那些产品&#xff0c;能跟卖那些不能跟卖&#xff0c;也有些卖家…

Nginx详解-安装配置等

目录 一、引言 1.1 代理问题 1.2 负载均衡问题 1.3 资源优化 1.4 Nginx处理 二、Nginx概述 三、Nginx的安装 3.1 安装Nginx 3.2 Nginx的配置文件 四、Nginx的反向代理【重点】 4.1 正向代理和反向代理介绍 4.2 基于Nginx实现反向代理 4.3 关于Nginx的location路径…

使用python做飞机大战

代码地址: 点击跳转

从.mat文件中导入数据到simulink进行FFT分析

1. 在matlab中准备数据 .mat 文件中包含时间向量和需要分析的数据 load(fcssiabc061302.mat);提取时间和需要分析的数据 time fcssiabc061302.X.Data; % 时间向量 signal fcssiabc061302.Y(1).Data; % A相电流数据 将数据转换为“structure with time”格式…

力扣67 二进制求和

文章目录 1. 题目链接2. 题目代码3.感受 1. 题目链接 二进制求和 2. 题目代码 class Solution { public:string addBinary(string a, string b) {vector<int> stringA;vector<int> stringB;int lengthOfA a.length();int lengthOfB b.length();for(int subscrip…

STELLA系统动态模拟技术及在农业、生态及环境等科学领域中的应用技术

STELLA是一种用户友好的计算机软件。通过绘画出一个系统的形象图形&#xff0c;并给这个系统提供数学公式和输入数据&#xff0c;从而建立模型。依据专业兴趣&#xff0c;STELLA可以用来建立各种各样的农业、生态、环境等方面的系统动态模型&#xff0c;为科研、教学、管理服务…

SpringBoot:集成机器学习模型进行预测和分析

引言 机器学习在现代应用程序中扮演着越来越重要的角色。通过集成机器学习模型&#xff0c;开发者可以实现智能预测和数据分析&#xff0c;从而提高应用程序的智能化水平。SpringBoot作为一个强大的框架&#xff0c;能够方便地集成机器学习模型&#xff0c;并提供灵活的部署和…

pycharm远程连接和conda环境参考博客自用整理

pycharm远程连接 pycharm的连接需要先用xftp把项目上传上去&#xff08;包括venv&#xff09;&#xff0c;似乎才能连 https://blog.csdn.net/weixin_41174300/article/details/134420981 注意要上传一份一模一样的&#xff0c;然后在deployment里面添加mapping 注意传输文件…

帮人安装打印机驱动踩过的坑

自从当了程序员&#xff0c;总被人认为是无所不能。安装系统&#xff0c;组装电脑都会。有啥只要跟电脑沾点边的事情都来找我。这不今天就被叫去帮人安装打印机驱动。 问题描述 以前老电脑都可以用打印机的&#xff0c;自从换新电脑后就不行了。别人可以用&#xff0c;就他的新…

AI替换:FaceFu V3.5.0软件下载,附教程

FaceFusion是一个基于WebUI的AI替换项目。 代码结构非常清晰&#xff0c;编码比较优秀&#xff0c;也正在变得更加实用。 前段时间也更新了不少内容。 今天统一通知一下&#xff0c;并且更新一下软件包。 具体的更新内容如下&#xff1a; V2.3.0更新内容&#xff1a; 引入…

类似Jira的在线项目管理软件有哪些?10 个主流的Jira替代方案

10 个 Jira 替代方案&#xff1a;PingCode、Worktile、Teambition、Redmine、Asana、monday.com、Zoho Projects、思码逸、Notion、Airtable。 Jira 是一款流行的项目管理工具&#xff0c;专为产品开发团队而设计。虽然它是一种多功能解决方案&#xff0c;几乎适用于任何类型的…

京东e卡怎么用?

京东618过去后&#xff0c;就没有多大购物欲望了&#xff0c;最后导致我手里还有好几张200块钱面值的e卡没地方用 本来说送朋友&#xff0c;但是又感觉面值太小了 最后还是在收卡云上把提取出来了&#xff0c;主要回收价格不错&#xff0c;而且到账也快&#xff0c;很方便

构建LangChain应用程序的示例代码:51、如何使用 Chroma 实现多模态检索增强生成 (RAG)

Chroma 多模态 RAG 许多文档包含多种内容类型&#xff0c;包括文本和图像。 然而&#xff0c;大多数 RAG 应用中&#xff0c;图像中捕获的信息往往被忽略。 随着多模态 LLM 的出现&#xff0c;如 GPT-4V&#xff0c;值得考虑如何在 RAG 中利用图像&#xff1a; 选项 1&…

如何在网络抓取过程中绕过 CAPTCHA 和 reCAPTCHA?

什么是 CAPTCHA&#xff1f; CAPTCHA&#xff0c;全称为 “Completely Automated Public Turing test to tell Computers and Humans Apart”&#xff08;完全自动化的公共图灵测试以区分计算机和人类&#xff09;&#xff0c;是一种用于识别网站访问者是否为真实人的测试。 这…

k8s学习--k8s群集ELK日志收集部署最详细的过程与应用(收集k8s群集日志)(图形化界面手把手教学)

文章目录 FilebeatFilebeat主要特点Filebeat使用场景 ELK简介Elasticsearch简介Elasticsearch主要特点Elasticsearch使用场景 Logstash简介Logstash主要特点Logstash使用场景 Kibana简介Kibana主要特点Kibana使用场景 简单理解 环境一、ELK集群部署1.软件安装2.软件配置及启动(…

Gitlab代码管理工具安装配置

前言&#xff1a; 没有真正的证书与域名建议使用httpip的方式在内网使用&#xff0c;不建议使用假的域名地址 一、安装前配置 #更改主机域名 hostnamectl set-hostname gitlab.dome.com bash #配置hosts 底部添加下面内容 vim /etc/hosts ############################ ip gi…

软件功能测试基础知识大揭秘,功能测试报告就找专业软件测评机构

软件功能测试是以软件产品的需求规格为基础&#xff0c;通过对软件功能的逐个测试&#xff0c;验证软件是否符合需求规格&#xff0c;是否能够正常执行各项功能操作。对于软件产品而言&#xff0c;功能测试是一项至关重要的工作&#xff0c;它能够发现软件中存在的功能缺陷、错…

104.二叉树的最大深度

给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;root [1,null,2] 输出…

10、matlab中字符、数字、矩阵、字符串和元胞合并为字符串并将字符串以不同格式写入读出excel

1、前言 在 MATLAB 中&#xff0c;可以使用不同的数据类型&#xff08;字符、数字、矩阵、字符串和元胞&#xff09;合并为字符串&#xff0c;然后将字符串以不同格式写入 Excel 文件。 以下是一个示例代码&#xff0c;展示如何将不同数据类型合并为字符串&#xff0c;并以不…