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

c++注意点(10)----设计模式(原型)

创建型模式

原型模式的目的就像文档编辑器中的 "复制粘贴" 功能

  • 当你复制一个文本段落(原型对象)
  • 粘贴后得到一个新段落(克隆对象)
  • 新段落与原段落内容相同,但可以独立修改
  • 这个过程避免了重新输入文本的成本,对应原型模式的核心思想。

        如果你有一个对象,你现在希望生成一个与之一模一样的复制品,该如何实现呢?流程一般是:新建一个属于相同类的对象,然后遍历原始对象的所有成员变量,并将成员变量复制到新对象里。但是这种情况有些问题.

    寻常做法的问题

            1.有些对象是有私有变量的,并不是所有的变量你都能访问到。

            2.即使你在该对象的类的内部实现一个复制操作,但是你仍然必须知道对象所属的类。所以你的代码必须依赖该类。即便你能够接受这样的要求,那也有别的问题。比如说你只知道对象所实现的接口,并不知道其所属的类。举例子:

            假设你在开发一个图形编辑器,支持多种形状(圆形、矩形、三角形等),这些形状都实现了Shape接口(包含draw()clone()等方法)。

    // 假设的复制函数(有问题的写法)
    Shape* copyShape(Shape* shape) {// 问题1:必须知道具体类型才能复制if (shape->type() == "Circle") {Circle* circle = dynamic_cast<Circle*>(shape);return new Circle(circle->radius, circle->color); // 依赖Circle类} else if (shape->type() == "Rectangle") {Rectangle* rect = dynamic_cast<Rectangle*>(shape);return new Rectangle(rect->width, rect->height); // 依赖Rectangle类}// ... 其他形状的判断return nullptr;
    }

            问题1:copyShape函数必须知道所有Shape的派生类(Circle、Rectangle等),一旦新增形状(如Triangle),必须修改这个函数,违反 “开闭原则”。

            问题2:如果shape是一个仅通过接口传递的对象(比如从外部库获取,你不知道它的具体类型),dynamic_cast和类型判断会失效,根本无法创建复制品。简单点说就是,除了Circle,Rectangle是你知道的外,如果是别的传进来,你就无法做出判断了。

    解决方法

            使用原型模式,原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口, 该接口让你能够克隆对象, 同时又无需将代码和对象所属类耦合。 通常情况下, 这样的接口中仅包含一个克隆方法。举例子:

    // 抽象接口:定义克隆方法
    class Shape {
    public:virtual ~Shape() = default;virtual std::unique_ptr<Shape> clone() const = 0; // 关键:自己复制自己virtual void draw() const = 0;
    };// 具体实现类:自己实现克隆逻辑
    class Circle : public Shape {
    private:int radius;std::string color;
    public:// 克隆自己:创建新Circle并复制状态std::unique_ptr<Shape> clone() const override {return std::make_unique<Circle>(*this); // 依赖自身,不依赖其他类}void draw() const override { /* 绘制圆形 */ }
    };class Rectangle : public Shape {// 同理,实现clone()复制自己
    };// 复制函数:完全依赖接口,不关心具体类型
    std::unique_ptr<Shape> copyShape(const Shape& shape) {return shape.clone(); // 调用对象自身的克隆方法,无需知道具体类型
    }
    1. 复制逻辑从外部函数转移到了对象内部(clone()方法由具体类自己实现)。
    2. 调用者只需通过Shape接口调用clone(),无需知道对象是Circle还是Rectangle
    3. 新增任何Shape派生类时,copyShape函数无需修改,只需该类实现clone()即可。

     再给一个例子,比如做文本编辑器。

    // 抽象原型类:定义克隆接口
    class DocumentElement {
    public:virtual ~DocumentElement() = default;virtual std::unique_ptr<DocumentElement> clone() const = 0;virtual void display() const = 0;virtual void setContent(const std::string& content) = 0;
    protected:std::string content; // 元素内容
    };// 具体原型1:文本段落
    class Paragraph : public DocumentElement {
    public:Paragraph(const std::string& text) {// 模拟复杂初始化过程(可能来自数据库或网络)std::cout << "创建新段落(耗时操作)" << std::endl;content = text;}// 克隆方法:通过复制当前对象创建新实例std::unique_ptr<DocumentElement> clone() const override {std::cout << "复制段落(快速操作)" << std::endl;// 创建新对象并复制当前状态auto copy = std::make_unique<Paragraph>("");copy->content = this->content;return copy;}void display() const override {std::cout << "段落内容:" << content << std::endl;}void setContent(const std::string& content) override {this->content = content;}
    };// 具体原型2:图片
    class Image : public DocumentElement {
    private:std::string imagePath; // 图片路径public:Image(const std::string& path, const std::string& desc) {// 模拟加载图片的耗时操作std::cout << "加载图片 " << path << "(耗时操作)" << std::endl;imagePath = path;content = desc;}std::unique_ptr<DocumentElement> clone() const override {std::cout << "复制图片(快速操作)" << std::endl;auto copy = std::make_unique<Image>("", "");copy->imagePath = this->imagePath;copy->content = this->content;return copy;}void display() const override {std::cout << "图片:" << imagePath << ",描述:" << content << std::endl;}void setContent(const std::string& content) override {this->content = content;}
    };// 文档编辑器:使用原型模式复制元素
    class DocumentEditor {
    public:// 复制任意文档元素static std::unique_ptr<DocumentElement> duplicate(const DocumentElement& prototype) {return prototype.clone(); // 调用原型的克隆方法}
    };int main() {// 1. 创建原始元素(成本高)auto originalPara = std::make_unique<Paragraph>("这是第一段文字");auto originalImage = std::make_unique<Image>("photo.jpg", "风景照");// 2. 复制元素(通过原型模式,成本低)auto copiedPara = DocumentEditor::duplicate(*originalPara);auto copiedImage = DocumentEditor::duplicate(*originalImage);// 3. 修改复制后的元素(不影响原始元素)copiedPara->setContent("这是复制后修改的段落");copiedImage->setContent("复制后的风景照描述");// 4. 展示结果std::cout << "\n原始元素:" << std::endl;originalPara->display();originalImage->display();std::cout << "\n复制后的元素:" << std::endl;copiedPara->display();copiedImage->display();return 0;
    }
    

    结果为:

    创建新段落(耗时操作)
    加载图片 photo.jpg(耗时操作)
    复制段落(快速操作)
    创建新段落(耗时操作)
    复制图片(快速操作)
    加载图片 (耗时操作)
    原始元素:
    段落内容:这是第一段文字
    图片:photo.jpg,描述:风景照
    复制后的元素:
    段落内容:这是复制后修改的段落
    图片:photo.jpg,描述:复制后的风景照描述

    优点

    1. 你可以克隆对象, 而无需与它们所属的具体类相耦合。
    2.  你可以克隆预生成原型, 避免反复运行初始化代码。
    3. 你可以更方便地生成复杂对象。
    4.  你可以用继承以外的方式来处理复杂对象的不同配置。
    http://www.lryc.cn/news/599153.html

    相关文章:

  • 安装pyarrow包
  • SAP-PP-MRPLIST
  • MyBatis高级应用实战指南
  • Movavi Video Editor v25.9.0 视频编辑软件中文特别版
  • 星图云开发者平台新功能速递 | 页面编辑器:全场景编辑器,提供系统全面的解决方案
  • 纳米编辑器之Nano 编辑器退出**的详细操作指南
  • IAR编辑器如何让左侧的工具栏显示出来?
  • Hive【安装 01】hive-3.1.2版本安装配置(含 mysql-connector-java-5.1.47.jar 网盘资源)
  • Linux 网络与 Vim 编辑器操作
  • Unity编辑器拓展 IMGUI与部分Utility知识总结(代码+思维导图)
  • 数据仓库深度探索系列 | 开篇:开启数仓建设新征程
  • react中 多个层级 组件数据同用 组件之间传值 usecontext useReducer
  • 滚动提示组件
  • MinIO:云原生对象存储的终极指南
  • GPU服务器与PC 集群(PC农场):科技算力双子星
  • 【PZ-KU060-KFB】——Kintex UltraScale 纯 FPGA 开发平台,释放高速并行计算潜能,高性价比的 FPGA 解决方案
  • 缓存HDC内容用于后续Direct2D绘制.
  • 云原生介绍
  • 云原生可观测-日志观测(Loki)最佳实践
  • 云原生 —— K8s 容器编排系统
  • iOS 日志查看实战指南,如何全面获取与分析 App 和系统日志
  • 单片机(STM32-ADC模数转换器)
  • 清理DNS缓存
  • 【物联网】基于树莓派的物联网开发【17】——物联网通信协议MQTT基础知识
  • 图论:并查集
  • 璞致 PZSDR-P101:ZYNQ7100+AD9361 架构软件无线电平台,重塑宽频信号处理范式
  • 图论:最小生成树
  • OneCode3.0 Gallery 组件前后端映射机制:从注解配置到前端渲染的完整链路
  • js基础概念-1
  • Mysql 日志 binlog redolog