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语言实现车辆信息管理系统攻略 1. 系统需求分析 在实现车辆信息管理系统之前,我们需要对系统进行需求分析,明确系统所需要实现的功能和对应的数据结构。下面是该系统的功能描述和数据结构设计: 功能描述 添加车辆信息 删除车辆信息 修改车辆信息 查询车辆信息 显示所有车辆信息 数据结构设计 车辆信息包括以下属性: 车牌号 车型 车主姓名 车主电话 因此,我们可以…

    C 2023年5月23日
    00
  • 解决找不到模块“xxx.vue”或其相应的类型声明问题

    要解决找不到模块“xxx.vue”或其相应的类型声明问题,需要进行以下几个步骤: 步骤一:确认模块路径是否正确 在使用import导入组件时,首先需要确认导入的组件路径是否正确。如果路径不正确,系统将会无法找到组件,然后报出找不到模块的错误。在Vue项目中,我们可以使用@符号来代表项目根路径。 示例一: 假设我们在组件src/components/myCom…

    C 2023年5月23日
    00
  • 内存的存储及其存储方式

    1. 内存存储2. 内存存储的方式3.为什么要有大小端模式的区分4.判断大小端模式 1.内存的存储:内存是由低地址向高地址进行存储。(即我们个位数为低地址位,而百,千位为高地址数) 为方便理解我们定义了一个变量a,如下 vs上方窗口栏:调试–>窗口–>内存–>内存1 在地址处输入&a,取a的地址 内存存储总结:我们可以看到数据…

    C语言 2023年4月18日
    00
  • C语言动态顺序表实例代码

    接下来我将详细讲解 C 语言动态顺序表的实现过程。首先我们需要先了解顺序表的概念,顺序表是一种线性表的存储结构,它在物理上采用一组连续的内存空间来存储线性表的数据元素,并且对于顺序表的元素,我们可以按照元素下标进行随机存取。接下来我们就可以开始进行动态顺序表的实现了。 动态顺序表的实现 初步设计 首先我们需要先建立一个动态顺序表结构体,它包含了以下几个基本成…

    C 2023年5月30日
    00
  • C++之CWnd窗口框架实例

    下面详细讲解一下“C++之CWnd窗口框架实例”的完整攻略。 C++之CWnd窗口框架实例 简介 CWnd是MFC框架中的一个基类,用于创建窗口。它具有以下特点: 可以接收和处理系统消息,如鼠标消息、键盘消息等; 可以在上面绘制图形; 可以在其上创建子控件等; 创建窗口 创建CWnd窗口的方法如下: BOOL CWnd::Create( LPCTSTR lp…

    C 2023年5月24日
    00
  • java 三元操作符用法说明

    Java的三元操作符也称为条件运算符(Ternary Operator),它是Java中唯一的一个三元运算符。它使用“?”和“:”符号,表示一个简单的条件转换操作,它通常用于简化if-else语句的使用。这个操作符的语法格式如下:expression1 ? expression2 : expression3。 其中,expression1为一个布尔表达式或者…

    C 2023年5月22日
    00
  • C语言流程控制之switch语句详解

    C语言流程控制之switch语句详解是本网站总结的一篇C语言教程文章,主要介绍了switch语句的用法和注意事项。本文将通过以下几个方面详细讲解: 1. switch语句的基本格式 switch语句由一个表达式和多个case组成,如下所示: switch(expression){ case constant-expression1: statement1; …

    C 2023年5月23日
    00
  • Linux中使用C语言的fork()函数创建子进程的实例教程

    下面是详细讲解创建子进程的实例教程。 什么是子进程? 在Linux系统中,一个进程可以创建其他进程。被创建的进程称为子进程,而新创建进程的进程称为父进程。子进程继承了父进程的所有属性和资源,包括进程ID、打开的文件描述符、信号处理方式等。 如何创建子进程? Linux中使用C语言提供了 fork() 函数来创建子进程。fork()函数是一个系统调用,调用后会…

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