(C++实现)——原型模式(Prototype Pattern)

2024-06-15 02:58

本文主要是介绍(C++实现)——原型模式(Prototype Pattern),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

解决的问题:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这个其实和C++的拷贝构造函数的作用是一致的,实际上就是动态抽取当前对象运行时的状态。


类图结构:     

客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象原型角色所要求的接口。


样例实现:

例子参照wuzhekai1985的简历的例子,代码拷贝如下:

[cpp]  view plain copy
  1. // CplusplusPrototype.cpp : Defines the entry point for the console application.  
  2. //  
  3. #include "stdafx.h"  
  4. #include<iostream>  
  5. #include<vector>  
  6. #include<assert.h>  
  7. using namespace std;  
  8. //父类    
  9. class Resume    
  10. {    
  11. protected:    
  12.     char *name;    
  13. public:    
  14.     Resume() {}    
  15.     virtual ~Resume() {}    
  16.     virtual Resume* Clone() { return NULL; }    
  17.     virtual void Set(char *n) {}    
  18.     virtual void Show() {}    
  19. };   
  20. class ResumeA : public Resume    
  21. {    
  22. public:    
  23.     ResumeA(const char *str);  //构造函数    
  24.     ResumeA(const ResumeA &r); //拷贝构造函数    
  25.     ~ResumeA();                //析构函数    
  26.     ResumeA* Clone();          //克隆,关键所在    
  27.     void Show();               //显示内容    
  28. };    
  29. ResumeA::ResumeA(const char *str)     
  30. {    
  31.     if(str == NULL) {    
  32.         name = new char[1];     
  33.         name[0] = '\0';     
  34.     }    
  35.     else {    
  36.         name = new char[strlen(str)+1];    
  37.         strcpy(name, str);    
  38.     }    
  39. }    
  40. ResumeA::~ResumeA() { delete [] name;}    
  41. ResumeA::ResumeA(const ResumeA &r) {    
  42.     name = new char[strlen(r.name)+1];    
  43.     strcpy(name, r.name);    
  44. }    
  45. ResumeA* ResumeA::Clone() {    
  46.     return new ResumeA(*this);    
  47. }    
  48. void ResumeA::Show() {    
  49.     cout<<"ResumeA name : "<<name<<endl;     
  50. }   
  51.   
  52. class ResumeB : public Resume    
  53. {    
  54. public:    
  55.     ResumeB(const char *str);  //构造函数    
  56.     ResumeB(const ResumeB &r); //拷贝构造函数    
  57.     ~ResumeB();                //析构函数    
  58.     ResumeB* Clone();          //克隆,关键所在    
  59.     void Show();               //显示内容    
  60. };    
  61. ResumeB::ResumeB(const char *str)     
  62. {    
  63.     if(str == NULL) {    
  64.         name = new char[1];     
  65.         name[0] = '\0';     
  66.     }    
  67.     else {    
  68.         name = new char[strlen(str)+1];    
  69.         strcpy(name, str);    
  70.     }    
  71. }    
  72. ResumeB::~ResumeB() { delete [] name;}    
  73. ResumeB::ResumeB(const ResumeB &r) {    
  74.     name = new char[strlen(r.name)+1];    
  75.     strcpy(name, r.name);    
  76. }    
  77. ResumeB* ResumeB::Clone() {    
  78.     return new ResumeB(*this);    
  79. }    
  80. void ResumeB::Show() {    
  81.     cout<<"ResumeB name : "<<name<<endl;     
  82. }   
  83.   
  84. int _tmain(int argc, _TCHAR* argv[])  
  85. {  
  86.     Resume *r1 = new ResumeA("A");    
  87.     Resume *r2 = new ResumeB("B");    
  88.     Resume *r3 = r1->Clone();    
  89.     Resume *r4 = r2->Clone();    
  90.     r1->Show(); r2->Show();    
  91.     //删除r1,r2    
  92.     delete r1; delete r2;       
  93.     r1 = r2 = NULL;    
  94.     //深拷贝所以对r3,r4无影响    
  95.     r3->Show(); r4->Show();    
  96.     delete r3; delete r4;    
  97.     r3 = r4 = NULL;       
  98.     return 0;  
  99. }  


带Prototype Manager的原型模式:

客户(Client)角色:客户端类向原型管理器提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。

代码实现如下:

[cpp]  view plain copy
  1. // CplusplusPrototype.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include<iostream>  
  6. #include<vector>  
  7. #include<assert.h>  
  8. using namespace std;  
  9. //父类    
  10. class Resume    
  11. {    
  12. protected:    
  13.     char *name;    
  14. public:    
  15.     Resume() {}    
  16.     virtual ~Resume() {}    
  17.     virtual Resume* Clone() { return NULL; }    
  18.     virtual void Set(char *n) {}    
  19.     virtual void Show() {}    
  20. };   
  21. class ResumeA : public Resume    
  22. {    
  23. public:    
  24.     ResumeA(const char *str);  //构造函数    
  25.     ResumeA(const ResumeA &r); //拷贝构造函数    
  26.     ~ResumeA();                //析构函数    
  27.     ResumeA* Clone();          //克隆,关键所在    
  28.     void Show();               //显示内容    
  29. };    
  30. ResumeA::ResumeA(const char *str)     
  31. {    
  32.     if(str == NULL) {    
  33.         name = new char[1];     
  34.         name[0] = '\0';     
  35.     }    
  36.     else {    
  37.         name = new char[strlen(str)+1];    
  38.         strcpy(name, str);    
  39.     }    
  40. }    
  41. ResumeA::~ResumeA() { delete [] name;}    
  42. ResumeA::ResumeA(const ResumeA &r) {    
  43.     name = new char[strlen(r.name)+1];    
  44.     strcpy(name, r.name);    
  45. }    
  46. ResumeA* ResumeA::Clone() {    
  47.     return new ResumeA(*this);    
  48. }    
  49. void ResumeA::Show() {    
  50.     cout<<"ResumeA name : "<<name<<endl;     
  51. }   
  52.   
  53. class ResumeB : public Resume    
  54. {    
  55. public:    
  56.     ResumeB(const char *str);  //构造函数    
  57.     ResumeB(const ResumeB &r); //拷贝构造函数    
  58.     ~ResumeB();                //析构函数    
  59.     ResumeB* Clone();          //克隆,关键所在    
  60.     void Show();               //显示内容    
  61. };    
  62. ResumeB::ResumeB(const char *str)     
  63. {    
  64.     if(str == NULL) {    
  65.         name = new char[1];     
  66.         name[0] = '\0';     
  67.     }    
  68.     else {    
  69.         name = new char[strlen(str)+1];    
  70.         strcpy(name, str);    
  71.     }    
  72. }    
  73. ResumeB::~ResumeB() { delete [] name;}    
  74. ResumeB::ResumeB(const ResumeB &r) {    
  75.     name = new char[strlen(r.name)+1];    
  76.     strcpy(name, r.name);    
  77. }    
  78. ResumeB* ResumeB::Clone() {    
  79.     return new ResumeB(*this);    
  80. }    
  81. void ResumeB::Show() {    
  82.     cout<<"ResumeB name : "<<name<<endl;     
  83. }   
  84.   
  85. class ResumeManager  
  86. {  
  87. private:  
  88.     vector<Resume *> mResume;  
  89. public:  
  90.     ResumeManager()  
  91.     {  
  92.   
  93.     }  
  94.     void add(Resume * resume)  
  95.     {  
  96.         mResume.push_back(resume);  
  97.     }  
  98.   
  99.      Resume * get(int index) const  
  100.     {  
  101.         assert(index>=0 && index<mResume.size());  
  102.         return mResume[index];  
  103.     }  
  104. };  
  105.   
  106. int _tmain(int argc, _TCHAR* argv[])  
  107. {  
  108.     ResumeManager *manager = new ResumeManager();  
  109.     Resume *r1 = new ResumeA("A");    
  110.     Resume *r2 = new ResumeB("B");    
  111.     manager->add(r1);  
  112.     manager->add(r2);  
  113.     manager->get(0)->Show();   
  114.     manager->get(1)->Show();    
  115.     Resume *r3 = manager->get(0)->Clone();    
  116.     Resume *r4 = manager->get(1)->Clone();   
  117.   
  118.     //删除r1,r2    
  119.     delete r1; delete r2;       
  120.     r1 = r2 = NULL;    
  121.     //深拷贝所以对r3,r4无影响    
  122.     r3->Show(); r4->Show();    
  123.     delete r3; delete r4;    
  124.     r3 = r4 = NULL;   
  125.     return 0;  
  126. }  

实现要点:

1.使用原型管理器,体现在一个系统中原型数目不固定时,可以动态的创建和销毁。

2.实现克隆操作,在.NET中可以使用Object类的MemberwiseClone()方法来实现对象的浅表拷贝或通过序列化的方式来实现深拷贝,在C++中就是拷贝构造函数的作用。

3.Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有稳定的接口。


效果:

1.它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。

2. Prototype模式允许客户只通过注册原型实例就可以将一个具体产品类并入到系统中,客户可以在运行时刻建立和删除原型。

3.减少了子类构造,Prototype模式是克隆一个原型而不是请求工厂方法创建一个,所以它不需要一个与具体产品类平行的Creater类层次。

4.Portotype模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响老系统。

5.产品类不需要非得有任何事先确定的等级结构,因为Prototype模式适用于任何的等级结构

6.Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。


适用性:

1. 当一个系统应该独立于他的产品创建、构成和表示时,需要使用原型模式

2. 当要实例化的类是在运行时刻指定时,如通过动态装载

3. 为了避免创建一个与产品类层次平行的工厂类层次时

4. 当一个类的实例只能有几个不同状态组合中的一种时,建立相应数目的原型并克隆他们可能比每次用合适的状态手工实例化该类更方便一些。



LCL_data原创于CSDN.NET【http://blog.csdn.net/lcl_data/article/details/8764228】

这篇关于(C++实现)——原型模式(Prototype Pattern)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062244

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)