//说些废话
。。这个模式毒死我了,真的毒死我了,毒了我8个小时,终于释怀了。。。特么一开始看这个模式,我想来想去,这尼玛不就直接调用个复制构造函数的事情吗。然后
while(1)
{
看来看去->查查资料->看看别人的blog->理解一下;
}
直接死循环了,8小时后的现在,终于break了,WTF,很晚了,不写那么多,简单说说重点贴个代码跑路。。
//部分资料来源
1.C++设计模式:http://www.jellythink.com/archives/105
2.程杰——大话设计模式
//适用场合(来源部分资料1)
1.当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象比较容易一些;
2.有的时候,我们需要一个对象在某个状态下的副本,此时,我们使用原型模式是最好的选择;例如:一个对象,经过一段处理之后,其内部的状态发生了变化;这个时候,我们需要一个这个状态的副本,如果直接new一个新的对象的话,但是它的状态是不对的,此时,可以使用原型模式,将原来的对象拷贝一个出来,这个对象就和之前的对象是完全一致的了;
3.当我们处理一些比较简单的对象时,并且对象之间的区别很小,可能就几个属性不同而已,那么就可以使用原型模式来完成,省去了创建对象时的麻烦了;
4.有的时候,创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程,让创建过程见鬼去吧。
//正文
上个代码再说话。。
#include <QCoreApplication>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
class Work
{
public:
Work(string a_string):name(a_string){}
Work(const Work& str);
Work& operator=(const Work &str)
{
if(this != &str)
{
Work strTemp(str);
string pTemp = strTemp.name;
strTemp.name = name;
name = pTemp;
}
return *this;
}
string name;
};
class Prototype
{
public:
Prototype(){}
virtual ~Prototype(){}
virtual Prototype* Clone() = 0;
};
class ConcretePrototype : public Prototype
{
public:
ConcretePrototype(Work *rhs_mywork,int num):mywork(rhs_mywork),mynum(num){}
virtual ~ConcretePrototype(){}
ConcretePrototype(const ConcretePrototype& rhs)
{
mywork = new Work(rhs.mywork->name);
//mywork = rhs.mywork;
mynum = rhs.mynum;
}
/*-------------------set---------------------*/
void setWord(string a_string)
{
mywork->name = a_string;
}
/*--------------------------------------------*/
/*------------------putout--------------------*/
void putout()
{
cout<<"mywork->name:"<<'\t'<<mywork->name<<endl;
cout<<"&mywork:"<<"\t"<<&mywork<<endl;
cout<<"&mywork->name"<<"\t"<<&mywork->name<<endl;
cout<<"mynum:"<<"\t\t"<<mynum<<endl;
cout<<"&mynum:"<<"\t\t"<<&mynum<<endl;
cout<<endl;
}
/*---------------------------------------------*/
/*-------------------clone---------------------*/
virtual ConcretePrototype* Clone()
{
return new ConcretePrototype(*this);
}
/*---------------------------------------------*/
private:
Work *mywork;
int mynum;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
string mystring = "wocao";
string mystring2 = "wocao2";
Work *mywork = new Work(mystring);
ConcretePrototype* conProA = new ConcretePrototype(mywork,10);
ConcretePrototype* conProB = conProA->Clone();
cout<<"A before setWord:"<<endl;
conProA->putout();
cout<<"B before setWord:"<<endl;
conProB->putout();
conProA->setWord(mystring2);
cout<<"A after setWord:"<<endl;
conProA->putout();
cout<<"B after setWord:"<<endl;
conProB->putout();
return a.exec();
}
毒死了。。这段代码其实有缺陷的,不过我不想改了,越改越难理解。。。
其实你可以看得出,Work类应该用一个Clone方法的,不然那里就没有用原型模式了,不过我注重说的是Prototype和他的子类,所以那个我就不管了。
其实原型模式,就做了一件事情,调用复制构造函数。 哦哦哦?就这样?
对,就这样。。只是要实现一下复制构造函数,不能用默认的,不然只能浅拷贝,下面详讲
原型模式(Protorype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。[DP]
=================================浅拷贝和深拷贝========================================
其实原型模式注意的地方有一个,很重要,就是复制构造函数的浅拷贝和深拷贝。
我们知道默认构造函数是浅拷贝的。
浅拷贝,对于值类型(包括string),则对该字段逐位复制,就如同我的子类里面int mynum一样,复制构造的时候,直接 = 赋值,他们的地址就不同了。
对于引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用统一对象。(意思就是不会new一个新对象,他们地址还是一样)
深拷贝,把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象,就如同我new Work一样。(默认复制构造函数 和 原型模式的复制构造函数 区别就在这)
=====================================================================================
理解完之后,clone就好简单了,直接return+调用一次复制构造函数。
//还有个事情说一下,我那个重载=操作符没有用上,只是记一下这种考虑了异常安全的对象间赋值操作。
//问题
1.
Q:原型模式有什么好处?
A:原型模式,从一个对象再创建另外一个可以定制的对象,而且不需要知道任何创建的细节。
一般在初始化信息不发生变化的情况下,隐藏对象创建细节,创建对象。
//坏处
说说坏处吧,你每一个子类都要写一个clone方法。这其实有点不切合实际的。
2.
Q:什么时候用原型模式?
A:最简单直接一句话概括,你要new一个跟现有对象一样的对象,或者只是很小部分属性有点不同。这就用咯。可以set来改那部分属性。
再提一下吧最后,原型模式其实就是: 用clone调用复制构造函数+重写复制构造函数(有类对象成员就深拷贝,只是值类型成员直接浅拷贝或者用默认)