设计模式:原型模式(Prototype)

设计模式:原型模式(Prototype)

  • 设计模式:原型模式(Prototype)
    • 模式动机
    • 模式定义
    • 模式结构
    • 时序图
    • 模式实现
    • 在单线程环境下的测试
    • 在多线程环境下的测试
    • 模式分析
    • 优缺点
    • 适用场景
    • 应用场景
    • 模式扩展
    • 应用实例
      • 实例 1:矩形对象克隆
      • 实例 2:图形原型注册表
    • 参考

设计模式:原型模式(Prototype)

原型模式(Prototype)属于创建型模式(Creational Pattern)的一种。

创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。

创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。

模式动机

如果你有一个对象, 并希望生成与其完全相同的一个复制品, 你该如何实现呢? 首先, 你必须新建一个属于相同类的对象。 然后, 你必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。

然而,并非所有对象都能通过这种方式进行复制, 因为有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的。

直接复制还有另外一个问题。 因为你必须知道对象所属的类才能创建复制品, 所以代码必须依赖该类。 即使你可以接受额外的依赖性, 那还有另外一个问题: 有时你只知道对象所实现的接口, 而不知道其所属的具体类, 比如可向方法的某个参数传入实现了某个接口的任何对象。

通过复制现有的实例来创建新的实例,无需知道相应类的信息。这就是原型模式(Prototype)的模式动机。

模式定义

原型模式(Prototype)属于创建型模式。

原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口, 该接口让你能够克隆对象, 同时又无需将代码和对象所属类耦合。

模式结构

原型模式(Prototype)包含如下角色:

  • 抽象原型类(Prototype):接口定义了一个抽象的克隆方法。
  • 具体原型类(Concrete Prototype):实现抽象原型类(接口)定义的克隆方法,提供一个具体的克隆方法来复制自己。
  • 客户端(Client):使用原型类的对象来实现具体的操作,即通过复制原型对象来创建新的对象。

在这里插入图片描述

时序图

略。

模式实现

抽象原型类 Prototype.h:

#ifndef _PROTOTYPE_H_
#define _PROTOTYPE_H_class Prototype
{
public:virtual Prototype* clone() = 0;
};#endif // !_PROTOTYPE_H_

具体原型类 ConcretePrototype1.h:

#ifndef _CONCRETE_PROTOTYPE_1_H_
#define _CONCRETE_PROTOTYPE_1_H_#include "Prototype.h"#include <string>class ConcretePrototype1 : public Prototype
{
private:std::string m_strTypeName;public:ConcretePrototype1(std::string name) : m_strTypeName(name) {};// 拷贝构造函数ConcretePrototype1(const ConcretePrototype1& rhs){m_strTypeName = rhs.m_strTypeName;}Prototype* clone() override{return new ConcretePrototype1(*this);}std::string getTypeName() const{return m_strTypeName;}
};#endif // !_CONCRETE_PROTOTYPE_1_H_

具体原型类 ConcretePrototype2.h:

#ifndef _CONCRETE_PROTOTYPE_2_H_
#define _CONCRETE_PROTOTYPE_2_H_#include "Prototype.h"#include <string>class ConcretePrototype2 : public Prototype
{
private:std::string m_strTypeName;public:ConcretePrototype2(std::string name) : m_strTypeName(name) {};// 拷贝构造函数ConcretePrototype2(const ConcretePrototype2& rhs){m_strTypeName = rhs.m_strTypeName;}Prototype* clone() override{return new ConcretePrototype2(*this);}std::string getTypeName() const{return m_strTypeName;}
};#endif // !_CONCRETE_PROTOTYPE_2_H_

在单线程环境下的测试

测试代码:

#include <iostream>
#include <stdlib.h>#include "ConcretePrototype1.h"
#include "ConcretePrototype2.h"using namespace std;int main()
{ConcretePrototype1* p1 = new ConcretePrototype1("A");ConcretePrototype2* p2 = (ConcretePrototype2*)p1->clone();cout << p1->getTypeName() << endl;cout << p2->getTypeName() << endl;delete p1;delete p2;system("pause");return 0;
}

运行结果:

在这里插入图片描述

在多线程环境下的测试

略。

模式分析

  • 原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口, 该接口让你能够克隆对象, 同时又无需将代码和对象所属类耦合。 通常情况下, 这样的接口中仅包含一个克隆方法。
  • 所有的类对克隆方法的实现都非常相似。该方法会创建一个当前类的对象, 然后将原始对象所有的成员变量值复制到新建的类中。 你甚至可以复制私有成员变量, 因为绝大部分编程语言都允许对象访问其同类对象的私有成员变量。
  • 支持克隆的对象即为原型。 当你的对象有几十个成员变量和几百种类型时, 对其进行克隆甚至可以代替子类的构造。

优缺点

优点:

  1. 可以克隆对象,而无需与它们所属的具体类相耦合。
  2. 可以克隆预生成原型,避免反复运行初始化代码,在创建大量对象时可以节省时间和资源,提高了对象创建的效率。
  3. 可以隐藏对象创建和初始化的复杂性,可以更方便地生成复杂对象,并且更容易管理和维护。
  4. 可以用继承以外的方式来处理复杂对象的不同配置。
  5. 可以在运行时动态添加和删除对象。
  6. 可以保护原始对象,防止意外修改对原对象产生影响。

缺点:

  1. 必须保证原始对象和克隆对象之间的区别,否则可能会产生副作用。
  2. 克隆包含循环引用的复杂对象可能会非常麻烦。
  3. 原型模式需要给对象添加一个克隆方法。但是,该方法可能不适用于所有对象类型,例如具有命令行参数的程序。

适用场景

在以下情况下可以使用原型模式:

  • 如果你需要复制一些对象,同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。
  • 如果子类的区别仅在于其对象的初始化方式,那么你可以使用该模式来减少子类的数量。 别人创建这些子类的目的可能是为了创建特定类型的对象。

在原型模式中,你可以使用一系列预生成的、 各种类型的对象作为原型。客户端不必根据需求对子类进行实例化, 只需找到合适的原型并对其进行克隆即可。

应用场景

  1. 细胞有丝分裂:原始细胞就是一个原型,它在复制体的生成过程中起到了推动作用。
  2. 孙悟空的七十二变。
  3. Object类:Java中的所有类都直接或间接继承自Object类,它提供了一个clone()方法,允许对象在克隆时使用它们的原型对象。
  4. Spring框架:在Spring框架中,原型范围bean使用原型模式。例如,在Spring中,可以将作用域设置为prototype,来创建一个bean的多个独立实例,这样每次在容器中注入bean时,将创建新的实例。

模式扩展

原型注册表 (Prototype Registry)提供了一种访问常用原型的简单方法,其中存储了一系列可供随时复制的预生成对象。 最简单的注册表原型是一个 名称 → 原型 的哈希表。 但如果需要使用名称以外的条件进行搜索,你可以创建更加完善的注册表版本。

在这里插入图片描述

应用实例

实例 1:矩形对象克隆

公司正在开发一个图形设计软件,其中有一个常用的图形元素是矩形。设计师在工作时可能需要频繁地创建相似的矩形,而这些矩形的基本属性(如颜色、宽度、高度)相同,但具体的位置可能不同。为了提高设计师的工作效率,请你使用原型模式设计一个矩形对象的原型。该原型可以根据用户的需求进行克隆,生成新的矩形对象。

#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;// 抽象原型类
class Prototype
{
public:virtual Prototype *clone() = 0;
};// 具体的矩阵类
class RectanglePrototype : public Prototype
{// 成员属性
private:string m_color;int m_height;int m_width;int x_pos;int y_pos;// 成员函数
public:RectanglePrototype(string color, int height, int width) : m_color(color), m_height(height), m_width(width){x_pos = 0;y_pos = 0;};// 重载克隆函数接口Prototype *clone() override{return new RectanglePrototype(*this);}// 信息打印void PrintInfo(){cout << "Color: " << m_color << ", Height: " << m_height << ", Width: " << m_width<< ", X pos: " << x_pos << ", Y pos: " << y_pos << endl;}void setPosition(int x, int y){x_pos = x;y_pos = y;}
};int main()
{string color = "Red";int height = 300, width = 100;// 创建原型对象RectanglePrototype *prototypeRectangle = new RectanglePrototype(color, height, width);prototypeRectangle->PrintInfo();// 克隆对象RectanglePrototype *clonedRectangle = (RectanglePrototype *)prototypeRectangle->clone();clonedRectangle->setPosition(50, 50);clonedRectangle->PrintInfo();delete clonedRectangle;clonedRectangle = nullptr;delete prototypeRectangle;prototypeRectangle = nullptr;system("pause");return 0;
}

运行结果:

在这里插入图片描述

实例 2:图形原型注册表

#include <iostream>
#include <string>
#include <unordered_map>
#include <stdlib.h>
using namespace std;// 抽象原型类
class Prototype
{
public:virtual Prototype *clone() = 0;virtual void draw() = 0;
};// 具体的矩阵类
class RectanglePrototype : public Prototype
{// 成员属性
private:string m_strTypeName;// 成员函数
public:RectanglePrototype(string name) : m_strTypeName(name){};// 重载克隆函数接口Prototype *clone() override{return new RectanglePrototype(*this);}void draw() override{cout << "Inside Rectangle::draw() method." << endl;}void setName(const string &name){m_strTypeName = name;}string getName() const{return m_strTypeName;}
};// 具体的正方形类
class SquarePrototype : public Prototype
{// 成员属性
private:string m_strTypeName;// 成员函数
public:SquarePrototype(string name) : m_strTypeName(name){};// 重载克隆函数接口Prototype *clone() override{return new SquarePrototype(*this);}void draw() override{cout << "Inside Square::draw() method." << endl;}void setName(const string &name){m_strTypeName = name;}string getName() const{return m_strTypeName;}
};// 具体的圆形类
class CirclePrototype : public Prototype
{// 成员属性
private:string m_strTypeName;// 成员函数
public:CirclePrototype(string name) : m_strTypeName(name){};// 重载克隆函数接口Prototype *clone() override{return new CirclePrototype(*this);}void draw() override{cout << "Inside Circle::draw() method." << endl;}void setName(const string &name){m_strTypeName = name;}string getName() const{return m_strTypeName;}
};class PrototypeRegistry
{
private:unordered_map<string, Prototype *> items;public:void addItem(string id, Prototype *p){items[id] = p;}Prototype *getById(string id){return items[id]->clone();}
};int main()
{RectanglePrototype *rect = new RectanglePrototype("Rectangle");SquarePrototype *square = new SquarePrototype("Square");CirclePrototype *circle = new CirclePrototype("Circle");PrototypeRegistry *prototypeRegistry = new PrototypeRegistry();prototypeRegistry->addItem("1", rect);prototypeRegistry->addItem("2", square);prototypeRegistry->addItem("3", circle);RectanglePrototype *clonedRect = (RectanglePrototype *)prototypeRegistry->getById("1");clonedRect->setName("my rectangle");cout << clonedRect->getName() << endl;clonedRect->draw();delete prototypeRegistry;delete rect;delete square;delete circle;delete clonedRect;system("pause");return 0;
}

运行结果:

在这里插入图片描述

参考

  1. https://design-patterns.readthedocs.io/zh-cn/latest/creational_patterns/creational.html
  2. https://www.runoob.com/design-pattern/prototype-pattern.html
  3. https://blog.csdn.net/weixin_45433817/article/details/131037102
  4. https://blog.csdn.net/weixin_45433817/article/details/131095164
  5. https://refactoringguru.cn/design-patterns/prototype
  6. https://www.cnblogs.com/ybqjymy/p/17534839.html
  7. https://www.jb51.net/article/55870.htm

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MQ本地消息事务表

纯技术方案水文特此记录 MQ本地消息事务表解决了什么问题&#xff1f; MQ本地事务表方案解决了本地事务与消息发送的原子性问题&#xff0c;即&#xff1a;事务发起方在本地事务执行成功后消息必须发出去&#xff0c;否则就丢弃消息。实现本地事务和消息发送的原子性&#xf…

Nvidia Orin/Jetson +GMSL/RLINC/VbyOne/FPDLink 同轴AI多相机同步车载视觉解决方案

在本次演讲中&#xff0c;介绍了多相机同步技术在自主机器中的应用情况&#xff0c;围绕无人配送小车、控制器视觉传感器方案升级、人形机器人三个典型案例中如何为客户提供高效的多相机同步解决方案进行了详细的讲解&#xff0c;并进一步介绍如何通过创新的多相机同步技术&…

Spring Boot 统一数据返回格式

在 Spring Boot 项目中&#xff0c;统一的数据格式返回是一种良好的实践&#xff0c;它提高了代码的可维护性和一致性&#xff0c;并改善了客户端与服务端之间的通信。本文将介绍如何在 Spring Boot 中实现统一的数据格式返回。 1 为什么需要统一数据返回格式 ⽅便前端程序员更…

VS Code开发Python配置和使用教程

在Visual Studio Code (VSCode) 中配置和使用Python进行开发是一个相对直接的过程&#xff0c;下面是一份简明的指南&#xff0c;帮助你从零开始设置环境&#xff1a; 1. 安装Visual Studio Code 首先&#xff0c;确保你已经安装了Visual Studio Code。如果还没有安装&#x…

2024年03月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 在Python中,hex(2023)的功能是?( ) A:将十进制数2023转化成十六进制数 B:将十进制数2023转化成八进制数 C:将十六进制数2023转化成十进制数 D:将八进制数2023转化成十进制数 答案:A …

JVM-之GC日志

一、 开启gc 日志 在项目中开启GC 日志打印后会查看gc 日志如下 nohup java -Xms768m -Xmx768m -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath./dumplog/dumplog.log -Xloggc:./dumplog/gc.log -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintHeapAtGC -jar xxxx…

188M2传奇BLUEM2引擎源码开源版附带编译教程2024最新开源

2024最新开源188M2传奇BLUEM2引擎源码开源2版最初开源版本附带编译教程 源码下载地址&#xff1a;极速云 如果需要优惠可以选择第一版最初开源188M2传奇BLUEM2引擎源码开源1版最初开源版本附带编译教程2024最新开源

Android 通过布局生成图片

通过布局生成图片 首先效果图 在竖屏的情况下通过&#xff0c;一般情况下&#xff0c;只要布局在页面上可见&#xff0c;并显示全&#xff0c;通过布局生成图片&#xff0c;都可以&#xff0c;但是横屏就不行了&#xff0c;会出现图片显示不完全的情况。 val bitmap Bitmap.c…

HubSpot企业商机管理和销售自动化:提升业务效率的利器

在当今数字化时代&#xff0c;企业出海已成为拓展市场、增加营收的重要途径。然而&#xff0c;如何高效地管理商机和实现销售自动化&#xff0c;成为许多企业面临的挑战。HubSpot作为一款强大的营销、销售和服务自动化平台&#xff0c;为企业提供了全方位的解决方案。今天运营坛…

图解 BERT 模型

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学. 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总合集&…

【Docker】docker-compose 常用命令

启动服务&#xff1a; docker-compose up 如果你想在后台运行服务&#xff0c;可以添加 -d 标志&#xff1a; docker-compose up -d 开启所有服务 docker-compose start 停止服务&#xff1a; docker-compose down 查看服务状态&#xff1a; docker-compose ps 查看…

5-21作业

流式域套接字 服务器端实现 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <semaphore.h> #include <…

【MiniCPM-V】win10本地部署OCR等性能测试

性能尝试 本地配置如下 --------------------------------------------------------------------------------------- | NVIDIA-SMI 546.80 Driver Version: 546.80 CUDA Version: 12.3 | |-----------------------------------------------------…

QQ名片满级会员装x助手HTML源码

源码介绍 QQ名片满级会员展示生成HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;保存素材去选择QQ个性名片-选择大图模板-把图上传照片墙即可 源码效果 源码下载 蓝奏云&#xff1a;http…

第18章-综合以上功能 基于stm32的智能小车(远程控制、避障、循迹) 基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图

这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能 18-按键和app按钮切换功能 根据上面介绍&#xff0c;我们的模式可…

城市空气质量数据爬取分析可视化

城市空气质量数据爬取分析可视化 一、效果展示二、完整代码2.1 数据爬取代码2.2 数据分析代码一、效果展示 先来看一下数据情况以及可视化效果,本项目使用了pyecharts绘制了日历图、雷达图、折线图、柱状图、饼图和平行坐标系。完整代码附后: 数据如下: 日历图: 饼图: …

Go源码--sync库(1)

简介 这篇主要介绍 sync.Once、sync.WaitGroup和sync.Mutex sync.Once once 顾名思义 只执行一次 废话不说 我们看源码 英文介绍直接略过了 感兴趣的建议读一读 获益匪浅 其结构体如下 Once 是一个严格只执行一次的object type Once struct {// 建议看下源码的注解&#xf…

【找出缺失的观测数据】python

思路&#xff1a; 主要在于分配剩余的部分分配问题 代码&#xff1a; class Solution:def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]:m len(rolls)total_sum (n m) * meantoset total_sum - sum(rolls)# 检查 toset 是否在可能的范围内i…

亚马逊高效广告打法及数据优化,亚马逊高阶广告打法课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89342733 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-亚马逊的广告漏斗和A9算法的升级变化.mp4 002.2-流量入口解析和广告的曝光机制.mp4 003.3-标签理论 .mp4 004.4-不同广告类…

影响所有股票、债券和ETF交易!一文看懂美国“T+1”结算新规

T1对投资者有何好处&#xff1f;有哪些风险&#xff1f;T1已经到来&#xff0c;T0还远吗&#xff1f; 美股将在本周迎来历史性时刻。 从当地时间5月28日开始&#xff0c;美股交易结算周期将由T2缩短至T1&#xff0c;即投资者当天卖出的股票&#xff0c;在交易后一个工作日就能…