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

news2024/11/22 1:44:26

通俗易懂地解读原型模式(Prototype Pattern)

什么是原型模式?

原型模式是一种创建型设计模式,它让我们可以通过复制(克隆)一个现有的对象,快速生成一个新的对象,而不需要再次通过类的实例化来创建。

用大白话来说:

如果你已经有一个模子(原型),你就可以用这个模子快速复制出新对象,就像用模型复制黏土雕塑一样。这样,你不需要每次都从零开始重新雕一个。


为什么需要原型模式?
  1. 节省时间和资源
    • 如果对象的创建很复杂(比如需要加载文件、调用外部服务等),直接复制一个现成的对象会快很多。
  2. 动态创建对象
    • 有时候,我们在运行时并不知道需要创建什么类型的对象,使用原型模式可以很灵活地克隆已有的对象。
  3. 避免类的依赖
    • 不需要在代码中直接实例化某个类,只需复制一个已有的实例即可。

举个例子

假如你在一个图形设计软件中设计了一些图形(比如圆形和矩形)。这些图形可能需要很多属性:大小、颜色、边框等。现在你需要快速生成这些图形的副本,而不是每次都手动创建。


原型模式的实现

下面我们通过一个简单的例子,演示如何用 C++ 实现原型模式:
模拟一个图形系统,通过原型模式实现图形(圆形、矩形)的快速复制。


完整代码
#include <iostream>
#include <string>
#include <memory> // 智能指针管理

// 抽象原型类
class Shape {
public:
    virtual ~Shape() = default;

    // 克隆方法,返回一个复制的对象
    virtual std::shared_ptr<Shape> clone() const = 0;

    // 显示图形信息
    virtual void draw() const = 0;
};

// 圆形类
class Circle : public Shape {
public:
    Circle(double radius) : radius_(radius) {}

    // 实现克隆方法
    std::shared_ptr<Shape> clone() const override {
        return std::make_shared<Circle>(*this); // 使用复制构造函数
    }

    // 显示圆形信息
    void draw() const override {
        std::cout << "绘制一个圆,半径为:" << radius_ << "\n";
    }

private:
    double radius_; // 半径
};

// 矩形类
class Rectangle : public Shape {
public:
    Rectangle(double width, double height) : width_(width), height_(height) {}

    // 实现克隆方法
    std::shared_ptr<Shape> clone() const override {
        return std::make_shared<Rectangle>(*this); // 使用复制构造函数
    }

    // 显示矩形信息
    void draw() const override {
        std::cout << "绘制一个矩形,宽为:" << width_ << ",高为:" << height_ << "\n";
    }

private:
    double width_;  // 矩形的宽
    double height_; // 矩形的高
};

// 客户端代码
int main() {
    // 创建一个圆形原型
    std::shared_ptr<Shape> circlePrototype = std::make_shared<Circle>(10.0);

    // 创建一个矩形原型
    std::shared_ptr<Shape> rectanglePrototype = std::make_shared<Rectangle>(20.0, 15.0);

    // 克隆圆形
    std::shared_ptr<Shape> clonedCircle = circlePrototype->clone();

    // 克隆矩形
    std::shared_ptr<Shape> clonedRectangle = rectanglePrototype->clone();

    // 显示克隆的图形
    clonedCircle->draw();    // 输出:绘制一个圆,半径为:10
    clonedRectangle->draw(); // 输出:绘制一个矩形,宽为:20,高为:15

    return 0;
}

运行结果

运行以上代码后,将输出以下结果:

绘制一个圆,半径为:10
绘制一个矩形,宽为:20,高为:15

代码逐步解析
  1. Shape 类:

    • 它是一个抽象原型类,定义了一个clone()方法,让所有子类实现复制的逻辑。
    • 同时,draw()方法用来显示图形信息。
  2. CircleRectangle 类:

    • 它们是具体的原型类,继承自Shape
    • 通过实现clone()方法,使用复制构造函数完成克隆操作。
    • draw()方法显示图形的具体属性。
  3. main 函数(客户端):

    • 客户端创建了一些原型对象(圆形和矩形)。
    • 使用这些原型的clone()方法,快速生成新的对象,并通过draw()方法显示它们。

通俗解释代码

  • clone() 就像一个“复印机”,你放进去一个原型对象(比如一个圆形),它会帮你复印出一个一模一样的新对象。
  • 不同的图形类(如圆形、矩形)都有自己的复制逻辑,但客户端只需要调用clone()就可以完成复制,而不需要关心复制细节。
  • 最终,你可以轻松地复制出大量类似的对象,而无需每次手动创建。

原型模式的优缺点
优点
  1. 提高效率:
    • 复制一个现成的对象比重新初始化一个对象快得多,特别是对象初始化代价很高时(比如加载资源或复杂计算)。
  2. 运行时动态创建:
    • 不需要在编译时确定对象类型,运行时可以基于原型创建实例,灵活性更高。
  3. 减少耦合:
    • 客户端只需要调用clone()方法,而无需关心具体对象的创建细节。
缺点
  1. 复杂的深拷贝:
    • 如果对象有嵌套结构(比如对象内部还有对象),需要实现复杂的深拷贝逻辑。
  2. 内存管理复杂:
    • 如果对象包含动态分配的资源,克隆时需要特别注意释放这些资源,否则可能导致内存泄漏。

适用场景
  1. 对象创建成本高:
    • 比如包含大量数据或需要复杂初始化的对象,可以通过克隆快速复制。
  2. 需要创建相似对象:
    • 比如游戏中的各种怪物、道具等,它们的基础属性相同,但某些细节可以在克隆后修改。
  3. 动态决定对象类型:
    • 如果程序在运行时需要根据情况创建对象,可以通过原型模式更灵活地实现。

总结

原型模式是一种非常实用的设计模式,特别是在需要创建大量相似对象或对象创建成本较高的情况下。通过clone()方法,我们可以轻松地复制一个对象,避免了重新初始化的麻烦。在实际开发中,原型模式广泛用于游戏开发、图形处理、文档复制等场景。希望通过这个简单的图形示例,你已经能够理解并掌握这一设计模式!

完整代码块

#include <iostream>
#include <string>
#include <memory> // 用于智能指针管理

// 抽象原型类
class Shape {
public:
    virtual ~Shape() = default;

    // 克隆方法,返回一个复制的对象
    virtual std::shared_ptr<Shape> clone() const = 0;

    // 显示图形信息
    virtual void draw() const = 0;

    // 设置名称,用于标识不同对象
    void setName(const std::string& name) {
        name_ = name;
    }

    // 获取对象名称
    std::string getName() const {
        return name_;
    }

private:
    std::string name_;
};

// 圆形类
class Circle : public Shape {
public:
    Circle(double radius) : radius_(radius) {}

    // 实现克隆方法
    std::shared_ptr<Shape> clone() const override {
        return std::make_shared<Circle>(*this); // 使用复制构造函数
    }

    // 显示圆形信息
    void draw() const override {
        std::cout << "圆形对象 [" << getName() << "],半径为:" << radius_ << "\n";
    }

private:
    double radius_; // 半径
};

// 矩形类
class Rectangle : public Shape {
public:
    Rectangle(double width, double height) : width_(width), height_(height) {}

    // 实现克隆方法
    std::shared_ptr<Shape> clone() const override {
        return std::make_shared<Rectangle>(*this); // 使用复制构造函数
    }

    // 显示矩形信息
    void draw() const override {
        std::cout << "矩形对象 [" << getName() << "],宽为:" << width_ << ",高为:" << height_ << "\n";
    }

private:
    double width_;  // 矩形的宽
    double height_; // 矩形的高
};

// 客户端代码
int main() {
    // 创建原始圆形对象
    std::shared_ptr<Shape> circlePrototype = std::make_shared<Circle>(10.0);
    circlePrototype->setName("原始圆形");

    // 创建原始矩形对象
    std::shared_ptr<Shape> rectanglePrototype = std::make_shared<Rectangle>(20.0, 15.0);
    rectanglePrototype->setName("原始矩形");

    // 克隆圆形
    std::shared_ptr<Shape> clonedCircle = circlePrototype->clone();
    clonedCircle->setName("拷贝圆形");

    // 克隆矩形
    std::shared_ptr<Shape> clonedRectangle = rectanglePrototype->clone();
    clonedRectangle->setName("拷贝矩形");

    // 显示原始和克隆的图形
    std::cout << "=== 原始对象 ===\n";
    circlePrototype->draw();
    rectanglePrototype->draw();

    std::cout << "\n=== 拷贝对象 ===\n";
    clonedCircle->draw();
    clonedRectangle->draw();

    return 0;
}

运行结果

运行以上代码后,输出如下:

=== 原始对象 ===
圆形对象 [原始圆形],半径为:10
矩形对象 [原始矩形],宽为:20,高为:15

=== 拷贝对象 ===
圆形对象 [拷贝圆形],半径为:10
矩形对象 [拷贝矩形],宽为:20,高为:15

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

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

相关文章

input file结合vue3和vant实现上传图片效果,并显示上传进度百分比%

这里写自定义目录标题 采用的dom结构是input file&#xff0c;label事件绑定&#xff0c;一下为代码传入参数为uploadNum实现效果如图上传中&#xff0c;图片1上传成功&#xff0c;图片2 采用的dom结构是input file&#xff0c;label事件绑定&#xff0c;一下为代码 传入参数为…

CSS优化file控件样式

<div class"file-box"><input type"button" class"btn" value"选择文件" /><inputtype"file"class"file"id"upimg"change"previewFiles"multiple/></div><!-- Vu…

AJAX笔记 (速通精华版)

AJAX&#xff08;Asynchronous Javascript And Xml&#xff09; 此笔记来自于动力节点最美老杜 传统请求及缺点 传统的请求都有哪些&#xff1f; 直接在浏览器地址栏上输入URL。点击超链接提交 form 表单使用 JS 代码发送请求 window.open(url)document.location.href urlwi…

某校园网登录界面前端加密绕过

前言 尝试对学校校园网登录框进行爆破&#xff0c;发现密码在前端被加密了 Burp抓包 抓包信息 DDDDD2022***&upass3d5c84b6fb1dc75987884f39c05b0e6a123456782&R10&R21&para00&0MKKey123456&v6ip From表单提交上来的文本这些参数&#xff0c;DDDD是…

《生成式 AI》课程 第3講 CODE TASK执行文章摘要的机器人

课程 《生成式 AI》课程 第3講&#xff1a;訓練不了人工智慧嗎&#xff1f;你可以訓練你自己-CSDN博客 任务1:总结 1.我们希望你创建一个可以执行文章摘要的机器人。 2.设计一个提示符&#xff0c;使语言模型能够对文章进行总结。 model: gpt-4o-mini,#gpt-3.5-turbo, import…

Github客户端工具github-desktop使用教程

文章目录 1.客户端工具的介绍2.客户端工具使用感受3.仓库的创建4.初步尝试5.本地文件和仓库路径5.1原理说明5.2修改文件5.3版本号的说明5.4结合码云解释5.5版本号的查找 6.分支管理6.1分支的引入6.2分支合并6.3创建测试仓库6.4创建测试分支6.5合并分支6.6合并效果查看6.7分支冲…

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具 文章目录 python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具项目背景技术栈用户界面核心功能实现结果展示完整代码总结 在现代软件开发中&#xff0c;测试接口的有效性与响应情况变得尤为重要。本文将指导…

JavaScript的类型转换

类型转换 &#xff1a; 隐式转换和显示转换 一般的&#xff0c;默认单选框和多选框传过来的值都是字符串 JavaScript是弱数据类型&#xff1a;JavaScript不知道变量属于哪种类型&#xff0c;需要赋值了才清楚。 缺点&#xff1a;使用表单、prompt获取过来的数据默认是字符串类…

Spring Boot中使用AOP和反射机制设计一个基于redis的幂等注解,简单易懂教程

由于对于一些非查询操作&#xff0c;有时候需要保证该操作是幂等的&#xff0c;该帖子设计幂等注解的原理是使用AOP和反射机制获取方法的类、方法和参数&#xff0c;然后拼接形成一个幂等键&#xff0c;当下一次有重复操作过来的时候&#xff0c;判断该幂等键是否存放&#xff…

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…

接口测试用例设计的关键步骤与技巧解析!

简介 接口测试在需求分析完成之后&#xff0c;即可设计对应的接口测试用例&#xff0c;然后根据用例进行接口测试。接口测试用例的设计也需要用到黑盒测试用例设计方法&#xff0c;和测试流程与理论章节的功能测试用例设计的方法类似&#xff0c;设计过程中还需要增加与接口特…

WPF下 DataGrid加入序号列

先上代码&#xff1a; <DataGrid Name"DGV" AutoGenerateColumns"False" Grid.Row"0" Grid.Column"0" HorizontalGridLinesBrush"RoyalBlue" VerticalGridLinesBrush"Tomato" CanUserAddRows"False&qu…

WebSocket详解、WebSocket入门案例

目录 1.1 WebSocket介绍 http协议&#xff1a; webSocket协议&#xff1a; 1.2WebSocket协议&#xff1a; 1.3客户端&#xff08;浏览器&#xff09;实现 1.3.2 WebSocket对象的相关事宜&#xff1a; 1.3.3 WebSOcket方法 1.4 服务端实现 服务端如何接收客户端发送的请…

大模型本地部署实践:Ollama+Open-WebUI(MacOS)

目录 什么是Ollama Ollama安装 对话界面可视化&#xff1f;Open-WebUI&#xff01; 安装Open-WebUI 什么是Ollama Ollama是一个为简化大语言模型本地部署与交互的开源框架。它提供了用户友好的接口&#xff0c;帮助开发者和模型爱好者在没有依赖外部API的基础上高效地运行、…

12万字 | 企业智慧数字化运营平台重构建设项目实施技术方案

本项目旨在推动企业数字化运营平台的重构&#xff0c;以支持组织改革和数字化转型战略的实施&#xff0c;提升企业智慧化运营管理能力。项目将优化订单受理流程&#xff0c;增强业务受理能力&#xff0c;提高客户服务体验和内部管控能力&#xff0c;同时提升营销资源管理的制度…

基于Lora通讯加STM32空气质量检测WIFI通讯-分享

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着环境污染问题的日益严重&#xff0c;空气质量的监测与管理已经…

cesium for unity的使用

先聊聊导入 看到这里的因该能够知道&#xff0c;官网以及网上绝大多数的方法都导入不进来&#xff0c;那么解决方法如下: 两个链接&#xff1a;按照顺序依次下载这两个tgz和zip&#xff0c;其中tgz为主要部分&#xff0c;zip为示例工程项目 如果您要查看示例工程项目的话&am…

数据结构_图的遍历

深度优先搜索遍历 遍历思想 邻接矩阵上的遍历算法 void Map::DFSTraverse() {int i, v;for (i 0; i < MaxLen; i){visited[i] false;}for (i 0; i < Vexnum; i){// 如果顶点未访问&#xff0c;则进行深度优先搜索if (visited[i] false){DFS(i);}}cout << endl…

MySQL时间字段TIMESTAMP和DATETIME

SELECT global.time_zone, session.time_zone;查询数据库的全局时区和当前会话的时区信息&#xff0c;一般如果使用navicat进行连接&#xff0c;没有显示指定时区信息&#xff0c;会默认使用system_time_zone。 可以使用 SET time_zone 08:00; SELECT global.time_zone, sess…

AQS 理解 及不可重入锁实现

由于目前水平有限&#xff0c;只是写出作者目前对 aqs的简单理解&#xff0c;有错误还请评论指证 AQS是什么 Aqs是java.util.concurrent 包下的一个抽象队列 同步器类&#xff0c;被简写为英文AQS&#xff0c; 我认为 可以把他理解 为一个 实现 自定义 锁的 一个具体的框架 …