C++设计模式之原型模式

下面我将详细讲解 C++ 设计模式之原型模式的完整攻略。

什么是原型模式?

原型模式是一种创建者模式,它通过复制现有对象来创建新对象,而不是直接实例化新对象。它通过在运行时动态生成对象副本的方式来创建新对象,避免了创建新对象的成本,并提高了性能。

原型模式的优缺点

优点:

  • 在运行时生成新对象,避免了创建新对象的成本。
  • 代码复杂度低,易于实现。
  • 可以实现对象动态配置。

缺点:

  • 所有的克隆方法都必须在导出类中实现。
  • 克隆方法是递归的,需要额外的递归调用开销。
  • 深克隆可能需要额外的编写代码和测试。

原型模式的实现方式

原型模式的实现方式可以采用两种方式来实现:浅拷贝和深拷贝。

浅拷贝:将一个对象复制到另一个对象中,新对象中的基本元素是源对象中相应元素的副本。这种方法比较简单,但如果源对象包含指向其他对象的指针,新对象中的指针将指向源对象中的相应指针所指向的地址,这种方法可能会引起问题。

深拷贝:将源对象的所有元素递归地复制到新对象中,使二者完全独立。这种方式比较安全,但开销比较大。

原型模式的实现步骤

  1. 定义一个抽象类或接口。
class ICloneable {
public:
    virtual ICloneable* Clone() = 0;
};
  1. 定义一个需要被克隆的对象。
class Person : public ICloneable {
public:
    string name;
    int age;
    Date birthday;
    vector<Address*> addresses;

    virtual ICloneable* Clone() {
        // 深拷贝实现
        Person* p = new Person(*this);
        // 指针地址修改为新对象的地址
        for (size_t i = 0; i < p->addresses.size(); i++) {
            Address* a = p->addresses[i];
            a = new Address(*a);
            p->addresses[i] = a;
        }
        return p;
    }
};
  1. 在需要克隆对象的位置进行调用,调用 Clone() 方法生成新对象。
int main() {
    Person* p1 = new Person();
    p1->name = "Tom";
    p1->age = 25;
    p1->birthday.year = 1996;
    p1->birthday.month = 7;
    p1->birthday.day = 5;
    p1->addresses.push_back(new Address("China", "Beijing"));
    p1->addresses.push_back(new Address("USA", "New York"));

    Person* p2 = (Person*)p1->Clone();
    // 修改新对象的值
    p2->name = "Jerry";
    p2->age = 30;
    p2->birthday.year = 1991;
    p2->birthday.month = 1;
    p2->birthday.day = 1;
    p2->addresses[0]->city = "Shanghai";
    p2->addresses[1]->city = "Los Angeles";

    return 0;
}

这样,在 main() 函数中,我们通过将原始对象 p1 传递到 Clone() 方法中生成新的对象 p2,并修改新对象的值。如果进行的是浅拷贝的实现方式,新对象 p2 将会和原始对象 p1 共享同一个地址空间,修改 p2 的值将会对 p1 也造成影响。而深拷贝由于同字符串常量池的使用后续会大批量申请内存非常占用,而weak_ptr又不稳定,为了解决深拷贝的问题,可以使用单例模式或者原型模式,进行共享部分的复用。

示例说明

下面给出两个典型的原型模式的示例,分别为“周报”和“简历”。

示例 1:周报

解释:每周要填写周报,内容格式固定。周报分为几个部分,例如工作内容、进度、问题、计划等,这些部分可能需要不断重复使用和填写。如果每次都需要手动填写,那么效率就会比较低。因此,这个时候,我们可以通过原型模式来解决这个问题。

首先,我们定义一个周报类,包含如下内容:

class WeeklyReport {
public:
    string name;
    string date;
    vector<string> workContent;
    vector<string> progress;
    vector<string> problems;
    vector<string> plan;

    ICloneable* Clone() {
        WeeklyReport* report = new WeeklyReport(*this);
        return report;
    }
};

同时,定义一个周报管理类,负责管理周报模板和实例:

class WeeklyReportManager {
public:
    unordered_map<string, WeeklyReport*> templates;

    // 注册模板
    void RegisterTemplate(string name, WeeklyReport* report) {
        templates[name] = report;
    }

    // 获取模板副本
    WeeklyReport* GetTemplate(string name) {
        return (WeeklyReport*)templates[name]->Clone();
    }
};

在运行时,我们只需加载多个周报模板,并且把需要的模板复制后修改,就可以快速地完成周报的填写。

示例 2:简历

解释:每次求职时,都需要撰写一份新的简历。如果每次都需要从头开始撰写,那么很难避免繁琐的重复劳动。同时,简历中的很多内容可能是可以公用的,例如教育经历、工作经历、项目经历等。这个时候,我们可以通过原型模式来实现简历的快速生成。

首先,我们定义一个简历类,包含如下内容:

class Resume {
public:
    string name;
    string email;
    vector<Education*> educations;
    vector<Work*> works;
    vector<Project*> projects;

    ICloneable* Clone() {
        Resume* resume = new Resume(*this);
        return resume;
    }
};

同时,定义一个简历模板管理类,负责管理简历模板和实例:

class ResumeTemplateManager {
public:
    unordered_map<string, Resume*> templates;

    // 注册模板
    void RegisterTemplate(string name, Resume* resume) {
        templates[name] = resume;
    }

    // 获取模板副本
    Resume* GetTemplate(string name) {
        return (Resume*)templates[name]->Clone();
    }
};

在运行时,我们只需加载多个简历模板,并且把需要的模板复制后修改,就可以快速地完成简历的撰写。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++设计模式之原型模式 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言中条件编译详解

    关于“C语言中条件编译详解”的攻略,我会详细讲解如下: 什么是条件编译? 条件编译就是根据某些条件来判断编译是否要执行某个代码块,也就是说可以根据不同的条件来编译不同的程序。 条件编译的语法 在 C 语言中,我们使用预处理器来实现条件编译,其语法如下: #ifdef macro // do something #endif 其中,“#ifdef”是条件编译的…

    C 2023年5月23日
    00
  • vscode C++远程调试运行(学习C++用)

    下面是vscode C++远程调试运行的攻略: 准备工作 首先,我们需要在本地安装 Visual Studio Code 和 C++ 编译器,以及在远程服务器上安装 gdbserver 和相应的 C++ 编译器。 安装 Visual Studio Code:进入Visual Studio Code官网,下载并安装最新版本。 安装 C++ 编译器:如果你已经安…

    C 2023年5月23日
    00
  • Python Json模块中dumps、loads、dump、load函数介绍

    Python Json模块中dumps、loads、dump、load函数介绍 一、Json模块介绍 Json(JavaScript Object Notation)是一种轻量级的数据交换格式,具有良好的可读性和易于编写的特点,因此广泛应用于网络传输和存储等方面。在Python中,我们可以使用内置的Json模块来进行Json数据的处理。Json模块主要包含以…

    C 2023年5月23日
    00
  • C语言实现抢红包算法

    C语言实现抢红包算法 在C语言中实现抢红包算法可以分为以下几个步骤: 步骤一:确定红包总金额以及红包个数 在C语言中,可以通过从键盘输入获取红包总金额和红包个数。可以用 scanf() 函数来实现,代码示例如下: printf("请输入红包总金额:"); scanf("%f",&total_money); pr…

    C 2023年5月22日
    00
  • Golang 的defer执行规则说明

    当前站点为标准的Markdown格式化文本提供支持。Markdown是一种轻量级的标记语言,通常由程序员和写作者使用,以便轻松将文本转换为HTML。 Golang 的defer执行规则说明 什么是defer defer是Golang中一个非常有用的关键字,用于确保函数调用在程序执行完当前代码块之后执行。defer被经常用于处理控制流,资源清理等任务,它为代码…

    C 2023年5月23日
    00
  • C语言编程C++编辑器及调试工具操作命令详解

    C语言编程C++编辑器及调试工具操作命令详解 1. 编辑器 1.1 什么是编辑器 编辑器是一种用于编写程序源码的软件,常用的编辑器有Visual Studio Code、Sublime Text、Notepad++等。 1.2 Visual Studio Code Visual Studio Code是一款免费开源的文本编辑器,可以在Windows、Linu…

    C 2023年5月23日
    00
  • C语言扫雷游戏的简单实现

    C语言扫雷游戏的简单实现攻略 一、游戏规则 扫雷是一款益智休闲游戏,其规则如下: 通过左键单击格子,可以将其翻开。如果格子为空白格,则会显示出周围8个格子中的雷数; 如果翻开的格子周围没有雷,则需要自动翻开周围的所有格子,直到边界或者有雷的格子; 通过右键单击格子,可以标记该格子为有雷的格子(或者是有疑问的格子)。一般来说,标记出所有的炸弹格子就算游戏胜利;…

    C 2023年5月23日
    00
  • C++中string类的常用方法实例总结

    C++中string类的常用方法实例总结 1. 概述 在C++中,字符串类型数据可以使用char数组和string类来实现。虽然char数组是C语言中常用的字符串表示方式,但是由于其操作起来非常麻烦,因此C++中更推荐使用string类。 C++中的string类提供了多种方法来处理字符串数据。本文将从常用方法的角度,总结并讲解C++中string类的一些常…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部