【有毒的设计模式】原型模式

来源:互联网 发布:在国外可以用淘宝吗 编辑:程序博客网 时间:2024/04/29 07:05

//说些废话

。。这个模式毒死我了,真的毒死我了,毒了我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调用复制构造函数+重写复制构造函数(有类对象成员就深拷贝,只是值类型成员直接浅拷贝或者用默认)


0 0