## 原型模式原理
原型模式相关原理可以参考菜鸟学院链接。其实大致原理说起来也很简单,就是不使用构造函数,而是采用clone接口进行对象的创建和原对象的复制,是一个设计模式中的一个创建型模式,而本篇博文主要讲述的是,大多数博文中都没有讲清楚的,为何不使用构造函数,而是使用clone接口函数进行原对象的创建和复制,原型模式的应用场景是什么。
我们来看:大多数博文中,所说,
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(构造函数不可以创建对象吗?构造后再赋值不就可以吗?)
主要解决:在运行期建立和删除原型;(构造函数不可以在运行期间使用吗?)
优点: 1、性能提高。 2、逃避构造函数的约束。(构造函数是犯了什么错,我们要嫌弃他?)
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。(这才是重点,快速生成原型对象)
那我来总结一下:本篇博文,最终要证明的一个观点。
原型模式主要解决的是,当构造函数需要大规模初始化资源情况下,原型模式可以定制化,将我们需要的修改的资源深拷贝,后续可以和原对象资源分离,修改后不会影响原对象,而不需要修改的资源直接浅拷贝即可,让他们指向相同的引用,那么我们相较于构造函数,不用修改的部分资源可以得以节省,即可快速创建一个相较于原对象定制化的对象。
话不多说,我们代码来解释。
代码设计:
孙悟空 分身 简单粗暴
属性:
1.姓名;
2.性别;
3.衣着;
4.攻击力;
5.分身后身份;
第一种分身:猪八戒
第二种分身:孙大娘
第三种分身:猴子猴孙
第四种分身:假猴
person.h
#pragma once
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
/*人物接口*/
typedef enum{
MAN = 0,
WOMAN
}GENDER;
class person
{
public:
char *name; //姓名
char gender; //性别:0->男 1->女
char *dressd; //衣着
int attack; //攻击力
char *pretendName; //伪装后身份
public:
~person()
{
if(name != nullptr)
delete name;
if(dressd != nullptr)
delete dressd;
if(pretendName != nullptr)
delete pretendName;
name = dressd = pretendName =nullptr;
}
person() = delete;
person(const char *name)
{
setPretendName("没有伪装");
int nameLen = strlen(name);
this->name = new char[nameLen+1];
strncpy(this->name,name,nameLen);
}
void setName(const char *name)
{
if(this->name != nullptr)
{
delete this->name;
}
int nameLen = strlen(name);
this->name = new char[nameLen+1];
strncpy(this->name,name,nameLen);
}
char* getName()
{
return name;
}
bool setGender(int gender)
{
if(gender < 0 || gender > 1)
{
return false;
}
this->gender = gender;
return true;
}
const char *getGender() const
{
switch (gender)
{
case 0:
return "男";
case 1:
return "女";
default:
return "未知性别";
};
}
bool setDressd(const char *dress)
{
if(this->dressd != nullptr)
{
delete this->dressd;
}
int dressLen = strlen(dress);
this->dressd = new char[dressLen + 1];
strncpy(this->dressd , dress , dressLen);
return true;
}
const char* getDress() const
{
return dressd;
}
void setAttack(int attack)
{
this->attack = attack;
}
int getAttack()
{
return attack;
}
bool setPretendName(const char* name)
{
if(this->pretendName != nullptr)
{
delete this->pretendName;
}
int nameLen = strlen(name);
this->pretendName = new char[nameLen + 1];
strncpy(this->pretendName , name , nameLen);
*(this->pretendName+nameLen) = '\0';
return true;
}
const char *getPretendName() const
{
return pretendName;
}
};
ostream& operator << (ostream& outp , person& c)
{
outp<<"姓名:"<<c.getName()<<endl;
outp<<"性别:"<<c.getGender()<<endl;
outp<<"衣着:"<<c.getDress()<<endl;
outp<<"攻击力:" <<c.getAttack()<<endl;
outp<<"伪装:"<<c.getPretendName()<<endl;
cout<<"***************************"<<endl<<endl;;
return outp;
}
#pragma once
#include <typeinfo>
#include "prototype.h"
#include "person.h"
class sunwukong : public Prototype , public person
{
public:
sunwukong():person("孙悟空")
{
setGender(MAN);
setAttack(100000);
setDressd("锁子黄金甲,凤翅紫金冠,藕丝步云履,如意金箍棒");
}
Prototype* Clone(person *soucePerson)
{
cout<<typeid(*soucePerson).name()<<endl; //本来准备使用typeid区分不同的子类 但是这里区分全部都是父类 不明原因。。。
return personCreate(soucePerson); //欢迎指导
}
sunwukong *personCreate(person *sourcePerson)
{
sunwukong * backPerson = nullptr;
if(0 != strcmp(sourcePerson->getName() , "孙悟空")) //孙大娘 猪八戒 猴子猴孙 因为其他都需要改变所以全部采用深拷贝方式进行
{
backPerson = new sunwukong(sourcePerson);
backPerson->name= this->name;
backPerson->setAttack(sourcePerson->getAttack());
backPerson->setDressd(sourcePerson->getDress());
if(0 == strcmp(sourcePerson->getGender(),"男"))
backPerson->setGender(MAN);
else
backPerson->setGender(WOMAN);
backPerson->setPretendName(sourcePerson->getName());
}
else if(0 == strcmp(sourcePerson->getName() , "孙悟空")) //真假悟空穿着姓名都引用悟空的
{
backPerson = new sunwukong(sourcePerson);
backPerson->setPretendName("假悟空");
backPerson->setAttack(0);
backPerson->name = const_cast<char *>(sourcePerson->getName());
backPerson->dressd = const_cast<char *>(sourcePerson->getDress());
backPerson->setGender(MAN);
}
else
{
return nullptr;
}
return backPerson;
}
private:
sunwukong(person *sourceType):person("孙悟空"){};
};
prototype.h
#pragma once
#include "person.h"
class Prototype // Prototype(抽象原型角色):是抽象类或者接口,用来声明clone方法。该方法是用来克隆自身的接口。
{
public:
virtual ~Prototype() = default;
virtual Prototype* Clone(person *soucePerson) = 0;
};
houzihousun.h
#pragma once
#include "person.h"
class houzihousun: public person
{
public:
houzihousun():person("猴子猴孙")
{
setGender(MAN);
setAttack(18);
setDressd("一张桃子形的面孔上,嵌着两颗闪着金光的眼睛,整天骨碌骨碌地直转,好像在打着什么主意.那小小的鼻子又塌又扁,而鼻孔却很大.鼻子下面有一张尖尖的大嘴巴,可爱极了!");
}
};
sundaniang.h
#pragma once
#include "person.h"
class sundaniang: public person
{
public:
sundaniang():person("孙大娘")
{
setGender(WOMAN);
setAttack(23);
setDressd("露出绿纱衫儿来,头上黄烘烘的插着一头钗环,鬓边插着些野花");
}
};
zhubajie.h
#pragma once
#include "person.h"
class zhubajie: public person
{
public:
zhubajie():person("猪八戒")
{
setGender(MAN);
setAttack(60);
setDressd("黑脸短毛,长喙大耳,穿一身青不青,蓝不蓝的梭布直裰,系一条花布手巾");
}
};
main.cpp
#include <iostream>
#include "prototype.h"
#include "sundaniang.h"
#include "zhubajie.h"
#include "houzihousun.h"
int main(void)
{
sunwukong *p = new sunwukong();
sunwukong *p_sundaniang = (sunwukong *)(p->Clone(new sundaniang()));
sunwukong *p_houzihousun = (sunwukong *)(p->Clone(new houzihousun()));
sunwukong *p_zhubajie = (sunwukong *)(p->Clone(new zhubajie()));
sunwukong *p_sunwukong = (sunwukong *)(p->Clone(p));
cout<<*p_sundaniang<<endl;
cout<<*p_houzihousun<<endl;
cout<<*p<<endl;
cout<<*p_zhubajie<<endl;
cout<<*p_sunwukong<<endl;
delete p;
delete p_houzihousun;
delete p_sundaniang;
delete p_zhubajie;
delete p_sunwukong;
p=p_sunwukong=p_zhubajie=p_houzihousun=p_sundaniang = nullptr;
return 0;
}