当前位置: 首页 > news >正文

四,设计模式-原型模式

目的

原型模式的产生是为了解决一个问题,即复制对象时对被复制对象所属类的依赖。当需要复制一个对象时,需要遍历对象中的所有成员并进行复制,但存在一些问题:某些成员对象可能是私有的无法访问。同时要复制某个对象,那就必须知道对象所属的类型,这就造成复制这个操作依赖了某个类型。

原型模式是一种创建型设计模式, 为所有支持克隆的对象声明了一个通用接口, 该接口能够克隆对象, 同时又无需将代码和对象所属类耦合,即通过对象进行复制,代替子类的构造。 

实现方式

原型模式的实现方式是将克隆的操作委托给被克隆的对象。方法是定义一个包含名字为clone()的接口,所有支持克隆的类型实现该方法,支持克隆的对象即为原型,具体如下:

  1. 创建原型接口, 并在其中声明克隆方法

  2. 原则上原型类必须另行定义一个以该类对象为参数的构造函数,构造函数必须复制参数对象中的所有成员变量值到新建实体中。 如果需要修改子类, 则必须调用父类构造函数, 让父类复制其私有成员变量值。在代码实现中使用标准库的make_unique方法,具体的拷贝操作交由该方法进行。

  3. 克隆方法的实现:每个类都必须显式重写克隆方法,否则, 克隆方法可能会生成父类的对象。这里使用智能指针以及标准库的make_unique方法。

代码如下:

#include <iostream>
#include <memory>class Prototype {
public:virtual std::unique_ptr<Prototype> clone() const = 0;virtual void print() const = 0;virtual ~Prototype() = default;
};class ConcretePrototypeA : public Prototype {
private:int value;
public:ConcretePrototypeA(int v) : value(v) {}std::unique_ptr<Prototype> clone() const override {return std::make_unique<ConcretePrototypeA>(*this);}void print() const override {std::cout << "ConcretePrototypeA with value: " << value << std::endl;}
};class ConcretePrototypeB : public Prototype {
private:std::string name;
public:ConcretePrototypeB(const std::string& n) : name(n) {}std::unique_ptr<Prototype> clone() const override {return std::make_unique<ConcretePrototypeB>(*this);}void print() const override {std::cout << "ConcretePrototypeB with name: " << name << std::endl;}
};void client(const Prototype& prototype) {auto cloned = prototype.clone();cloned->print();
}int main() {ConcretePrototypeA prototypeA(42);ConcretePrototypeB prototypeB("PrototypeB");std::cout << "Cloning Prototype A:\n";client(prototypeA);std::cout << "\nCloning Prototype B:\n";client(prototypeB);return 0;
}

补充

其实对于这个原型模式的实现,我自己理解“从对象直接拷贝”,更像是对内存块的直接复制(类似memcpy),但如果是这样,那么对包含虚函数、指针等数据和操作的类对象直接这么干就会有很大问题。而Java的类库中本身实现了原型模式(Cloneable),提供了克隆的接口,后来我查到C++的标准库方法std::make_unique也可以做到同样的事情,虽然和我浅显的理解有些出入,但终究是解决了一些疑问。

http://www.dtcms.com/a/349644.html

相关文章:

  • 设计模式5-代理模式
  • 无锁队列的设计与实现
  • jdbc相关内容
  • 基于TimeMixer的帕金森语音分类:WAV音频输入与训练全流程
  • 基于开源 AI 智能名片链动 2+1 模式 S2B2C 商城小程序的新开非连锁品牌店开业引流策略研究
  • 云计算之中间件与数据库
  • 蜂窝物联网模组在冷链运输行业的应用价值
  • 盲盒经济新风口:盲盒抽谷机小程序系统开发全解析
  • 审核问题——首次进入APP展示隐私政策弹窗
  • JavaWeb(八)EL表达式,JSTL标签
  • 阿里云短信验证码服务
  • 奔赴少年CIIU携专辑《我们的出发》正式出道 与J.Y. Park同台首秀备受关注
  • 基于SpringBoot的招聘管理系统【2026最新】
  • 【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描
  • C# NX二次开发:绘图区控件和指定矢量控件详解
  • [MH22D3开发笔记]2. SPI,QSPI速度究竟能跑多快,双屏系统的理想选择
  • 基于WebTransport(底层QUIC)实现视频传输(HTML+JavaScript)
  • C语言基础:(二十五)预处理详解
  • 从0到1:用 Qwen3-Coder 和 高德MCP 助力数字文旅建造——国庆山西游
  • Rust面试题及详细答案120道(58-65)-- 集合类型
  • 解锁处暑健康生活
  • Docker:部署Nginx
  • week4-[一维数组]数码个数
  • Gemini 2.5 Flash-Lite 与 GPT-5-mini:高性能低成本模型,如何选择?
  • 链表OJ习题(1)
  • redis-缓存-持久化
  • 使用 Gemini CLI作为 Claude Code的 subagent
  • OC-MVC模式下的折叠cell
  • 利用 Python 爬虫获取 1688 商品详情 API 返回值说明(代码示例)实战指南
  • 爬虫基础学习-爬取网页项目