出国做博士后网站,资阳网站seo,华为云企业邮箱登录入口,个人建站网站什么是原型模式#xff1f; 原型模式⼀种创建型设计模式#xff0c;该模式的核⼼思想是基于现有的对象创建新的对象#xff0c;⽽不是从头开始创建。在原型模式中#xff0c;通常有⼀个原型对象#xff0c;它被⽤作创建新对象的模板。新对象通过复制原型对象的属性和状态来…什么是原型模式 原型模式⼀种创建型设计模式该模式的核⼼思想是基于现有的对象创建新的对象⽽不是从头开始创建。在原型模式中通常有⼀个原型对象它被⽤作创建新对象的模板。新对象通过复制原型对象的属性和状态来创建⽽⽆需知道具体的创建细节。 Prototype模式说简单点就是提供了一个clone, 通过已存在对象进行新对象创建。clone实现和具体的实现语言相关在C中我们通过拷贝构造函数实现。
那为啥要写clone的接口来实现这个目的呢直接使用拷贝构造不香么知乎中看到陈硕大佬对此的一个回答觉得豁然开朗。
Prototype 的意义在于你拿到一个 基类指针 Base*
它指向某个 派生类 Derived 对象
你想克隆出 Derived对象但代码中不写出 Derived 的具体类型
因为有很多派生类这种情况下你用构造函数是搞不定的。
switch-case 是 bad smells 。
另外这里考虑 virtual 的性能损失是主次不分
构造对象需要分配内存这开销比一次虚函数调用大多了。
–陈硕在知乎中的回答复习拷贝构造函数实现 在学习原型模式之前我们先来看一下C中深拷贝和先拷贝问题 UML 两种角色
1. prototype(抽象原型类) Monster类
2. ConcretePrototype 具体原型类在clone方法中 return一个自己的对象 M_undead,M_Element,M_Mechanic 那么什么时候才能使用这个原型对象呢
我们以 魔兽争霸 这款游戏中的 分身系英雄为例当 剑圣 出镜像的时候5狗齐飞分身斧这些道具或者技能使用的时候分裂出来的这些英雄都应该有当前英雄的这些属性然后将属性微调就可以例如分身的攻击力只有原先的30%受到伤害是原先的150%。就可以用 原型模型。
这里的核心是 魔兽争霸的英雄 属性太多了还有6个框框的物品栏分裂的瞬间都要将这些属性拷贝过去。--也就是说 如果对象的内部数据比较复杂多变并且在创建对象的时候希望爆出对象的当前状态那么用原型模式显然比用工厂方法模式更合适 工厂方法模式和原型模式在创建对象时的异同点 a。都不需要程序员知道所创建对象所属的类名
b.工厂方法模式中的createMonster仍旧属于根据类名来生成新对象
c 原型模式clone是根据现有对象来生成新对象会调用 copy构造方法 。
d 原型模型不像工厂模式不需要额外的等级结构创建多个工厂类 原型模式的优缺点
如果创建新对象的背部数据比较复杂且多变原型模式创建对象的效率可能高的多
需要在clone中完成对象的拷贝特别是深拷贝和浅拷贝问题但是一般都调用 copy构造方法
当前copy构造函数中也可以调用 operator 的重写。
这样也可以使用 完成拷贝 原型模式和直接 M_undead(m_undead1) 有啥区别 既然原型模式的 也是调用 copy构造函数那么直接用 如下的代码不就行了吗为啥还弄个原型模式
M_undead m_undead2 M_undead(m_undead1) 1. C才有 copy构造java C#并没有设计模式是独立于变成 语言存在的因此原型模式的存在是有意义的。
2.你拿到一个 基类指针 Base* 它指向某个 派生类 Derived 对象 你想克隆出 Derived对象但代码中不写出 Derived 的具体类型 因为有很多派生类这种情况下你用构造函数是搞不定的。 switch-case 是 bad smells 。 代码
在代码中还复习了 移动构造函数和 移动operator运算符的重写。 // 原型模型//原型模式⼀种创建型设计模式
//该模式的核⼼思想是基于现有的对象创建新的对象
//⽽不是从头开始创建。在原型模式中通常有⼀个原型对象
//它被⽤作创建新对象的模板。
//新对象通过复制原型对象的属性和状态来创建⽽⽆需知道具体的创建细节。
//
//Prototype模式说简单点就是提供了一个clone,
//通过已存在对象进行新对象创建。
//clone实现和具体的实现语言相关
//在C中我们通过拷贝构造函数实现。
//
//那为啥要写clone的接口来实现这个目的呢
//直接使用拷贝构造不香么
//
//Prototype 的意义在于你拿到一个 基类指针 Base*
//它指向某个 派生类 Derived 对象
//你想克隆出 Derived对象但代码中不写出 Derived 的具体类型
//因为有很多派生类这种情况下你用构造函数是搞不定的。
//switch - case 是 bad smells 。
//另外这里考虑 virtual 的性能损失是主次不分
//构造对象需要分配内存这开销比一次虚函数调用大多了。//
#define _CRT_SECURE_NO_WARNINGS
#include iostream
#include stdlib.h
#include stdio.h
#include stdint.h
using namespace std;//在学习原型模式之前需要先复习一下 C 的 深拷贝浅拷贝问题。
//涉及到的知识点拷贝构造函数重写赋值运算符函数移动构造函数重写移动赋值运算符函数class Teacher
{
public:Teacher() default;//default 表示C编译器给无参数的构造方法生成函数体//有参数的构造方法Teacher(int age,string sname,char* name,char *othername,char **stuname):_age(age),_sname(sname), _othername(othername),_stuname(stuname){cout Teacher 有参数的构造方法被调用 endl;strcpy(_name, name);}//拷贝构造函数 正常的写法//Teacher(const Teacher obj) {// this-_age obj._age;// strcpy(_name, obj._name);// this-_sname obj._sname;// // //如果原先的othername不为nullptr则先要将原先的othername delete掉。实际代码中// if (this-_othername! nullptr) {// delete this-_othername;// this-_othername nullptr;// }// if (this-_stuname ! nullptr) {// for (int i 0; i 5; i)// {// delete this-_stuname[i];// this-_stuname[i] nullptr;// }// delete this-_stuname;// this-_stuname nullptr;// //delete [] this-_stuname;// }// if (obj._othername ! nullptr) {// int othernamelen strlen(obj._othername) 1;// this-_othername (char *)malloc(sizeof(char) * othernamelen);// strcpy(this-_othername,obj._othername);// }// if (obj._stuname ! nullptr) {// this-_stuname (char **)malloc(sizeof(char *) * 5);// for (int i 0; i 5; i)// {// if (obj._stuname[i] ! nullptr) {// int stunamelen strlen(obj._stuname[i]) 1;// this-_stuname[i] (char *)malloc(sizeof(char *) *stunamelen);// strcpy(this-_stuname[i],obj._stuname[i]);// }// }// }//}//拷贝构造函数Teacher(const Teacher obj) {cout Teacher 拷贝构造函数被调用 endl;*this obj;}//operator 函数 重写Teacher operator( const Teacher obj) {cout Teacher 赋值运算符函数被调用 endl;this-_age obj._age;strcpy(_name, obj._name);this-_sname obj._sname;//如果原先的othername不为nullptr则先要将原先的othername delete掉。实际代码中if (this-_othername ! nullptr) {free( this-_othername);this-_othername nullptr;}if (this-_stuname ! nullptr) {for (int i 0; i 5; i){free( this-_stuname[i]);this-_stuname[i] nullptr;}free( this-_stuname);this-_stuname nullptr;//delete [] this-_stuname;}if (obj._othername ! nullptr) {int othernamelen strlen(obj._othername) 1;this-_othername (char *)malloc(sizeof(char) * othernamelen);strcpy(this-_othername, obj._othername);}if (obj._stuname ! nullptr) {this-_stuname (char **)malloc(sizeof(char *) * 5);for (int i 0; i 5; i){if (obj._stuname[i] ! nullptr) {int stunamelen strlen(obj._stuname[i]) 1;this-_stuname[i] (char *)malloc(sizeof(char *) *stunamelen);strcpy(this-_stuname[i], obj._stuname[i]);}}}return *this;}//移动拷贝函数Teacher( Teacher obj) {cout Teacher 移动构造函数被调用 endl;*this move(obj);}//移动赋值运算符 重写Teacher operator(Teacher obj) {cout Teacher 移动赋值运算符 被调用 endl;this-_age obj._age;strcpy(_name, obj._name);this-_sname obj._sname;//如果原先的othername不为nullptr则先要将原先的othername delete掉。实际代码中if (this-_othername ! nullptr) {free( this-_othername);this-_othername nullptr;}if (this-_stuname ! nullptr) {for (int i 0; i 5; i){free( this-_stuname[i]);this-_stuname[i] nullptr;}free( this-_stuname);this-_stuname nullptr;//delete [] this-_stuname;}if (obj._othername ! nullptr) {int othernamelen strlen(obj._othername) 1;this-_othername (char *)malloc(sizeof(char) * othernamelen);strcpy(this-_othername, obj._othername);}if (obj._stuname ! nullptr) {this-_stuname (char **)malloc(sizeof(char *) * 5);for (int i 0; i 5; i){if (obj._stuname[i] ! nullptr) {int stunamelen strlen(obj._stuname[i]) 1;this-_stuname[i] (char *)malloc(sizeof(char *) *stunamelen);strcpy(this-_stuname[i], obj._stuname[i]);}}}//if (obj._othername ! nullptr) {free(obj._othername);obj._othername nullptr;}if (obj._stuname!nullptr) {for (int i 0; i 5; i){if (obj._stuname[i] !nullptr) {free( obj._stuname[i]);obj._stuname[i] nullptr;}}free( obj._stuname);obj._stuname nullptr;}return *this;}// 写一个clone函数内部调用 拷贝构造方法Teacher* clone() {return new Teacher(*this);}~Teacher() {if (this-_othername ! nullptr) {free(this-_othername);this-_othername nullptr;}if (this-_stuname ! nullptr) {for (int i 0; i 5; i){free(this-_stuname[i]);this-_stuname[i] nullptr;}free(this-_stuname);this-_stuname nullptr;//delete [] this-_stuname;}}
public:int _age 0 ;string _sname ;char _name[128] {0};char *_othername nullptr;char **_stuname nullptr;
};
void printTea(Teacher *tea) {if (tea NULL) {return;}printf(------ printTea start ------\n);printf(tea-age %d,tea-name %s,tea-othername%s\n,tea-_age,tea-_name,tea-_othername);for (size_t j 0; j 5; j){printf(tea-stuname[%d] %s, ,j, tea-_stuname[j]);}printf(\n);printf(------ printTea end ------\n);}
int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口std::cout Hello World!\n;Teacher tea;tea._age 10;strcpy(tea._name, tea---name);tea._sname teasname;tea._othername (char *)malloc(sizeof(char) * 128);memset(tea._othername,0,sizeof(char) * 128);strcpy(tea._othername, teaothername);tea._stuname (char**)malloc(sizeof(char *) * 5);memset(tea._stuname, 0, sizeof(char *) * 5);for (int i 0; i 5; i){tea._stuname[i] (char *)malloc(sizeof(char) * 128);memset(tea._stuname[i], 0, sizeof(char) * 128);sprintf(tea._stuname[i], teastuname%d, i 100);}printTea(tea);cout --------- endl;Teacher tea1 tea;printTea(tea1);cout ----1111111111----- endl;Teacher tea2 ;tea2 tea;printTea(tea2);cout ----2222222222----- endl;Teacher tea3 move(tea);printTea(tea3);cout ----333333333----- endl;Teacher tea4;tea4 move(tea3);printTea(tea4);// 原型模式Teacher.clone方法的调用Teacher *tea5 tea4.clone();printTea(tea5);delete tea5;//这里有些Teacher 的 析构函数因此delete 会调用析构函数
} 继承中的代码 namespace _nmsp2
{//怪物父类class Monster{public://构造函数Monster(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}virtual ~Monster() {} //做父类时虚构函数应该为虚函数public:virtual Monster* clone() 0; //具体的实现在子类中进行//public:// void setlife(int tmplife)// {// m_life tmplife;// }protected: //可能被子类访问的成员所以用protected修饰//public://怪物属性int m_life; //生命值int m_magic; //魔法值int m_attack; //攻击力};//亡灵类怪物class M_Undead :public Monster{public://构造函数M_Undead(int life, int magic, int attack) :Monster(life, magic, attack){cout 一只亡灵类怪物来到了这个世界 endl;}//拷贝构造函数//..........留给大家自己写virtual Monster* clone(){//return new M_Undead(300, 50, 80); //创建亡灵类怪物return new M_Undead(*this); //触发拷贝构造函数的调用来创建亡灵类怪物/*Monster * pmonster new M_Undead(300, 50, 80); //创建亡灵类怪物//pmonster-m_life m_life;pmonster-setlife(m_life);pmonster-m_magic m_magic;pmonster-m_attack m_attack;return pmonster;*/}//...其他代码略};//元素类怪物class M_Element :public Monster{public://构造函数M_Element(int life, int magic, int attack) :Monster(life, magic, attack){cout 一只元素类怪物来到了这个世界 endl;}//拷贝构造函数M_Element(const M_Element tmpobj) :Monster(tmpobj) //初始化列表中注意对父类子对象的初始化{cout 调用了M_Element::M_Element(const M_Element tmpobj)拷贝构造函数创建了一只元素类怪物 endl;}virtual Monster* clone(){//return new M_Element(200, 80, 100); //创建元素类怪物return new M_Element(*this);}//...其他代码略};//机械类怪物class M_Mechanic :public Monster{public://构造函数M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack){cout 一只机械类怪物来到了这个世界 endl;}//拷贝构造函数M_Mechanic(const M_Mechanic tmpobj) :Monster(tmpobj) //初始化列表中注意对父类子对象的初始化{cout 调用了M_Mechanic::M_Mechanic(const M_Mechanic tmpobj)拷贝构造函数创建了一只机械类怪物 endl;}virtual Monster* clone(){//return new M_Mechanic(400, 0, 110); //创建机械类怪物return new M_Mechanic(*this);}//...其他代码略};//全局的用于创建怪物对象的函数/*void Gbl_CreateMonster2(Monster* pMonster){Monster* ptmpobj nullptr;if (dynamic_castM_Undead*(pMonster) ! nullptr){ptmpobj new M_Undead(300, 50, 80); //创建亡灵类怪物}else if (dynamic_castM_Element*(pMonster) ! nullptr){ptmpobj new M_Element(200,80, 100); //创建元素类怪物}else if (dynamic_castM_Mechanic*(pMonster) ! nullptr){ptmpobj new M_Mechanic(400, 0, 110); //创建机械类怪物}if (ptmpobj ! nullptr){//这里就可以针对ptmpobj对象实现各种业务逻辑//......//不要忘记释放资源delete ptmpobj;}}*/void Gbl_CreateMonster2(Monster* pMonster){Monster* ptmpobj pMonster-clone(); //根据已有对象直接创建新对象不需要知道已有对象所属的类型//这里就可以针对ptmpobj对象实现各种业务逻辑//......//不要忘记释放资源delete ptmpobj;}
} 调用 _nmsp2::M_Mechanic myPropMecMonster(400, 0, 110); //创建一只机械类怪物对象作为原型对象以用于克隆目的_nmsp2::Monster* pmyPropEleMonster new _nmsp2::M_Element(200, 80, 100); //创建一只元素类怪物对象作为原型对象以用于克隆目的//这里可以直接new也可以通过工厂模式创建原型对象取决于程序员自己的洗好。//....._nmsp2::Monster* p_CloneObj1 myPropMecMonster.clone(); //使用原型对象克隆出新的机械类怪物对象_nmsp2::Monster* p_CloneObj2 pmyPropEleMonster-clone(); //使用原型对象克隆出新的元素类怪物对象_nmsp2::Monster* p_CloneObj3 new _nmsp2::M_Mechanic(myPropMecMonster);//可以对p_CloneObj1、p_CloneObj2所指向的对象进行各种操作实现具体的业务逻辑//......//释放资源//释放克隆出来的怪物对象delete p_CloneObj1;delete p_CloneObj2;//释放原型对象堆中的delete pmyPropEleMonster;_nmsp2::Monster* pMonsterObj new _nmsp2::M_Element(200, 80, 100);_nmsp2::Gbl_CreateMonster2(pMonsterObj);delete pMonsterObj;