文章目录

  • 1. 理论知识
  • 2. 逻辑模板代码
  • 3. 应用
    • 3.1 应用1: 改写简历
    • 3.2 深浅拷贝的问题 ==*==
    • 3.3 深拷贝的嵌套使用

思考: 原型模式跟装饰器模式的区别?

本文核心:

 WorkExperience* clone(){WorkExperience *w = new WorkExperience();*w = *this; // 深拷贝一个相同的自己, 注意如果this中有指针, 需要在对这个指针类进行clone方法的实现, 这样层层嵌套, 就实现了整体的深拷贝return w; // 将当前的this深拷贝给w, 返回}

1. 理论知识

当遇到需要复制的实例时, 我们就用到了原型模式, 比如打印20份自己的简历, 一个自己的简历类, 然后实例化一个简历A后, 在实例化 B=A, 但是很抱歉, 这里的B=A其实B是A的引用, 并不是真实的实例, 所以需要用到克隆技术

原型模式: 用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象; 其实就是从一个对象在创建另外一个可定制的对象, 并且不需要知道创建的任何细节;

**使用场景: **
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。

原型模式的优缺点
原型模式的优点: 底层的二进制实现拷贝,相比起new操作可以节约性能
原型模式的缺点: 构造函数没有调用,牺牲了灵活性

2. 逻辑模板代码

// 原型模式起始就是从一个对象在创建另一个可定制的对象, 而且不需要知道任何创建细节
// 原型类
class Prototype{private:string id;
public:Prototype(string id): id(id){}Prototype() : id("ndy"){}string get(){return id;}virtual Prototype* clone() = 0; // 这个方法是关键
};// 具体原型类
class ConcretePrototype_1 : public Prototype{private:public:ConcretePrototype_1(string id): Prototype(id){}ConcretePrototype_1() {}// 相当于实现了深拷贝virtual Prototype *clone(){// 先开辟等量空间ConcretePrototype_1 *p = new ConcretePrototype_1();*p = *this; // 在将当前类深拷贝给上面空间return p;}
};// 客户端
int main(int argc, char const *argv[]){Prototype *p1 = new ConcretePrototype_1("nb");Prototype *c1 = p1->clone();// ConcretePrototype_1 *p1 = new ConcretePrototype_1("nb");// ConcretePrototype_1 *c1 = (ConcretePrototype_1 *)p1->clone();cout << c1->get() <<endl; // 输出nbdelete p1, c1;return 0;
}

3. 应用

3.1 应用1: 改写简历

创建一个简历实例A, 在从这个实例A中修改数据变成实例B

// 简历
class Resume{private:string name, sex, age, timeArea, company;
public:Resume(string name) : name(name){}// 设置个人信息void setPersonalInfo(string sex, string age) {this->sex = sex;this->age = age;}// 设置工作经历void setWorkExperience(string timeArea, string company){this->company = company;this->timeArea = timeArea;}// 显示void Display(){cout << "个人信息:" << name << " " << age << " " << sex << " " << timeArea << " " << company <<endl;}Resume* clone(){Resume *r = new Resume("");*r = *this;return r;}
};// 这里实现了一个功能为除了name不变, 其他的信息可以改变的不同的简历
// 比如我做了一个简历V1, 然后简历V2是在V1的基础上修改了些信息做的
int main(int argc, char const *argv[])
{Resume *nb = new Resume("nb");nb->setPersonalInfo("男", "25");nb->setWorkExperience("2015-2-2", "tencent");Resume *b2 = (Resume*) nb->clone();b2->setPersonalInfo("女" , "27");Resume *b3 = (Resume*) b2->clone();b3->setWorkExperience("2020-5-5", "baidu");b2->Display();nb->Display();b3->Display();delete nb, b2, b3;return 0;
}

3.2 深浅拷贝的问题 *

上面应用遇到一个问题, 当成员变量有指针时, 默认拷贝还是浅拷贝, 比如工作经历如果是一个类, 那么实例指针只会在拷贝的时候拷贝指针, 而不会拷贝实例, 这样拷贝的指针依然指向实例未变, 如果看不懂, 请看下面的例子

// 工作经历类
class WorkExperience{private:string workDate, company;
public:void set(string workDate, string company){this->workDate = workDate, this->company = company;}string get_workDate(){return this->workDate;}string get_company(){return this->company;}
};// 简历
class Resume{private:string name, sex, age;WorkExperience *work = nullptr;
public:Resume(string name) : name(name), work(new WorkExperience()){}// 设置个人信息void setPersonalInfo(string sex, string age) {this->sex = sex;this->age = age;}// 设置工作经历void setWorkExperience(string timeArea, string company){work->set(timeArea, company);}// 显示void Display(){cout << "个人信息:" << name << " " << age <<" " << sex << " " << work->get_workDate() << " " << work->get_company() <<endl;}Resume* clone(){Resume *r = new Resume("");*r = *this; // 注意: 这里由于work是类, 默认拷贝是引用, 因此这里进行拷贝, // 虽然其他成员变量都是深拷贝, 但是work这个指针也是拷贝了指针, 并没有拷贝指针所指的对象return r;}
};// 这里实现了一个功能为除了name不变, 其他的信息可以改变的不同的简历
// 比如我做了一个简历V1, 然后简历V2是在V1的基础上修改了些信息做的
int main(int argc, char const *argv[])
{Resume *nb = new Resume("nb");nb->setPersonalInfo("男", "25");nb->setWorkExperience("2015-2-2", "tencent");Resume *b2 = (Resume*) nb->clone();b2->setPersonalInfo("女" , "27");Resume *b3 = (Resume*) b2->clone();b3->setWorkExperience("2020-5-5", "baidu");b2->Display();nb->Display();b3->Display();delete nb, b2, b3;return 0;
}
个人信息:nb 27 女 2020-5-5 baidu
个人信息:nb 25 男 2020-5-5 baidu
个人信息:nb 27 女 2020-5-5 baidu

就会发现所有的工作经验都变成最后修改的值了, 这是因为浅拷贝, 无论怎么修改都是在修改第一个实例的工作经验

3.3 深拷贝的嵌套使用

在类里面都增加一个clone方法来克隆(深拷贝)对象, 这样就方便了下面使用该类进行深拷贝的操作了

// 工作经历类
class WorkExperience{private:string workDate, company;
public:void set(string workDate, string company){this->workDate = workDate, this->company = company;}string get_workDate(){return this->workDate;}string get_company(){return this->company;}WorkExperience* clone(){ // b. 当调用这个方法时, 深拷贝了一个新workWorkExperience *w = new WorkExperience();*w = *this;return w; // 将当前的this深拷贝给w, 返回}
};// 简历
class Resume{private:string name, sex, age;WorkExperience *work = nullptr;
public:Resume(string name) : name(name), work(new WorkExperience()){} // a. 第一次创建简历时, 同时创建了工作经历类Resume(){}~Resume(){ // 由于每个resume都对应一个workif(work != nullptr){delete work}}// 设置个人信息void setPersonalInfo(string sex, string age) {this->sex = sex;this->age = age;}// 设置工作经历void setWorkExperience(string timeArea, string company){work->set(timeArea, company);}// 显示void Display(){cout << "个人信息:" << name << " " << age <<" " << sex << " " << work->get_workDate() << " " << work->get_company() <<endl;}Resume* clone(){Resume *r = new Resume(); // c. 创建干净的简历时, 此时r->work还是空的*r  =  *this;  // 此时r->work已经是this->work的深拷贝了, 但是里面的work指针还是指向this的work实例r->work = work->clone(); // 这样就深拷贝了一个新的work给r, 在返回r, 就是全新的了return r;}
};// 这里实现了一个功能为除了name不变, 其他的信息可以改变的不同的简历
// 比如我做了一个简历V1, 然后简历V2是在V1的基础上修改了些信息做的
int main(int argc, char const *argv[])
{Resume *nb = new Resume("nb");nb->setPersonalInfo("男", "25");nb->setWorkExperience("2015-2-2", "tencent");Resume *b2 = (Resume*) nb->clone();b2->setPersonalInfo("女" , "27");Resume *b3 = (Resume*) b2->clone();b3->setWorkExperience("2020-5-5", "baidu");b2->Display();nb->Display();b3->Display();delete nb, b2, b3;return 0;
}

C++ 模式设计 原型模式(深拷贝/克隆)相关推荐

  1. 一口气讲完设计模式(单例模式、工厂模式、原型模式、建造者模式、适配器、桥梁模式)

    设计模式 使用设计模式,可以让我们的代码具有更好的可读性.可扩展性.可读性.重用性.符合高内聚低耦合的特点.作为程序员,是我们经常听到的概念,也是我们程序员必须深入学习,了解的知识. 设计模式种类 该 ...

  2. 【原型模式】原型模式深入分析

    文章目录 1. 原型模式 2.原型模式的应用场景 3. 原型模式的通用写法 3.1 先创建 IProtoType 接口 3.2 创建具体需要克隆的类 3.3 测试代码: 3.3.1 运行结果: 浅克隆 ...

  3. 软件系统设计-4-建造者模式、原型模式

    1. 建造者模式 1.1. 模式动机 无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮.方向盘.发送机等各种部件.而对于大多数用户而言,无须知道这些部 ...

  4. Java设计模式(工厂模式>抽象工厂模式和原型模式)

    Java设计模式Ⅱ 1.工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 2.抽象工厂模式 3.总结 4.原型模式 4.1 原型模式 4.2 浅拷贝 4.3 深拷贝 5.建造者模式 1.工厂模式 ...

  5. 建造者模式与原型模式/builder模式与prototype模式/创建型模式

    建造者模式 定义 用于简化复杂对象的创建 JDK中的建造者模式 java.lang.StringBuilder中的append()方法,每次调用后返回修改后的对象本身. public StringBu ...

  6. [19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)

    一.建造者模式 本质:分离了对象子组件的单独构造(由Builder负责)和装配的分离(由Director负责),从而可以构建出复杂的对象,这个模式适用于:某个对象的构建过程十分复杂 好处:由于构建和装 ...

  7. 创建型模式:原型模式

    前方高能:<一故事一设计模式>PDF 电子书已经上线,关注公众号即可获取. 个人公众号原文: 创建型模式:原型模式 五大创建型模式之五:原型模式. 简介 姓名 :原型模式 英文名 :Pro ...

  8. 设计模式-Prototype模式(原型模式)

    目录 原型模式是什么? 为什么要用原型模式? 原型模式是什么? Prototype模式:不根据类来生成实例,而是根据实例来生成新实例. 怎么理解呢?举个例子,就是比如现在我们只有两个类,球(Ball) ...

  9. 第二课 工厂模式和原型模式

    一. 制作一个抽象产品:螺丝 制作2个具体产品:8mm螺丝 和 6mm螺丝 使用简单工厂来实现这个场景,并且让客户端通过简单工厂来获取具体产品. 然后扩展一个7mm螺丝,你会发现这要修改简单工厂的代码 ...

最新文章

  1. 解决导入第三方图片JS出现403问题
  2. 30.IntellJ Idea 导入已存在的Maven项目
  3. matlab条件判断配合输出
  4. 复变函数与积分变换-手写笔记
  5. python百度地图api经纬度_从百度地图API接口批量获取地点的经纬度
  6. 第五天2017/04/06(下午3:静态链接库(Lib))
  7. 【pmcaff】社交媒体时代,村姑如何找到真爱?
  8. IPHONE 64位和32位
  9. LeetCode 124. Binary Tree Maximum Path Sum
  10. HTML+CSS实现菜单的3D翻转特效
  11. 常见视频编码比较大全 常见视频解码技术资料1
  12. 天 月_财务结算专业术语快来学习!月结和月结30天的区别
  13. 通过朋友间推广APP,根本不可行
  14. (自适应手机版)中英文双语响应式新材料类网站源码 HTML5新型环保材料网站织梦dedecms模板
  15. Arduino-ESP32闪存文件插件程序搭建和上传
  16. v3.exo是什么文件_exo是什么文件?
  17. Unity 实现2D地面挖洞!涂抹地形(碰撞部分,方法一)
  18. Day 112/200 Macbook Pro 电脑按键脱落怎么办?
  19. 游戏设计模式阅读笔记19——优化模式(空间分区)
  20. selenium webdriver使用

热门文章

  1. 线程、进程与赛车游戏
  2. 【邢不行|量化小讲堂系列23-Python量化入门】不用再自己写技术指标了 | TA-lib视频教程
  3. rr与hr_RR OR HR傻傻分不清楚——带你区分临床研究中的“3R”
  4. 什么是hidl_protobuf 在通过 hidl 接口传输时,是不是应该用 string 啊
  5. python之汉诺塔问题详解
  6. EduCoder-Linux与Python编程2021(类的基础语法)- 第3关:绑定与方法调用
  7. 如果国产手机都用鸿蒙,华为自己都不用鸿蒙,那么会有哪个国产手机品牌会使用?...
  8. 【写博客常用】sublime 快捷键
  9. docker初学小结
  10. dw中HTML做表格代码,DW制作怎样在网页中插入表格?