原型模式
1.概述
原型模式就是通过复制现在已经存在的对象来创建一个新的对象。
工作原理:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。
2.角色
客户(Client)角色:客户端类向原型管理器提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体原型类所需的接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。
3优缺点
优点:
1)允许动态地增加或减少产品类。且增加新产品对整个结构没有影响。
2)提供简化的创建结构。工厂方法常需要有一个与产品类相同的等级结构,而原型模式不需要。
3)产品类不需要非得有任何事先确定的等级结构,因为原型模式适用于任何的等级结构。
缺点:
1) 每一个类必须配备一个克隆方法。
浅复制和深复制
浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象。
深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.
4 与new的区别
有的时候,创建实例的构造函数非常的复杂,在执行这个构造函数时会消耗较长的时间,同时,这个构造函数中的一些信息又没有什么变化
那么直接使用 new 来创建这样一个实例就显得太昂贵了。这时候就可以使用原型模式。
5. 使用场景
以下的几个场景的时候,可能使用原型模式更简单也效率更高。
1)当一个系统应该独立于它的产品创建、构成和表示时。
2)当要实例化的类是在运行时刻指定时,例如,通过动态装载。
3)为了避免创建一个与产品类层次平行的工厂类层次时。
4)当一个类的实例只能有几个不同状态组合中的一种时。
比如在画图工具里,要画圆只需要拖动工具条的画圆工具到绘图区即可,而不需要从头开始一点一点的画一个圆,而且如果需要不同大小和颜色的圆,只需要复制几个圆,然后再修改他们的大小和颜色即可。
6.代码实现
1)不带原型管理器
http://blog.csdn.net/wuzhekai1985/article/details/6667020
1 class Resume 2 { 3 protected: 4 char *name; 5 public: 6 virtual Resume* Clone(){return NULL;} 7 virtual void Set(char *n){} 8 virtual void Show(){} 9 }; 10 11 class ResumeA: public Resume 12 { 13 public: 14 ResumeA(const char *str) 15 { 16 if(str == NULL) 17 { 18 name = new char[1]; 19 name[0] = '\0'; 20 } 21 else 22 { 23 name = new char[strlen(str)+1]; 24 strcpy(name, str); 25 } 26 }//构造函数 27 ResumeA(const ResumeA &r) 28 { 29 name = new char[strlen(r.name)+1]; 30 strcpy(name, r.name); 31 }//拷贝构造函数 32 ResumeA* Clone() 33 { 34 return new ResumeA(*this); 35 } 36 void Show() 37 { 38 cout<<"ResumeA name : "<<name<<endl; 39 } 40 }; 41 42 43 class ResumeB: public Resume 44 { 45 public: 46 ResumeB(const char *str) 47 { 48 if(str == NULL) 49 { 50 name = new char[1]; 51 name[0] = '\0'; 52 } 53 else 54 { 55 name = new char[strlen(str)+1]; 56 strcpy(name, str); 57 } 58 }//构造函数 59 ResumeB(const ResumeB &r) 60 { 61 name = new char[strlen(r.name)+1]; 62 strcpy(name, r.name); 63 }//拷贝构造函数 64 ResumeB* Clone() 65 { 66 return new ResumeB(*this); 67 } 68 void Show() 69 { 70 cout<<"ResumeB name : "<<name<<endl; 71 } 72 }; 73 74 75 int main() 76 { 77 Resume *r1 = new ResumeA("A"); 78 Resume *r2 = new ResumeB("B"); 79 Resume *r3 = r1->Clone(); 80 Resume *r4 = r2->Clone(); 81 r1->Show(); r2->Show(); 82 //删除r1,r2 83 delete r1; delete r2; 84 r1 = r2 = NULL; 85 //深拷贝所以对r3,r4无影响 86 r3->Show(); r4->Show(); 87 delete r3; delete r4; 88 r3 = r4 = NULL; 89 } 90 91
2)带原型管理器
只需在原有的代码中添加原型管理器代码即可
http://blog.csdn.net/lcl_data/article/details/8764228
#pragma once #include "stdafx.h" #include <iostream> #include<vector> using namespace std; class Resume { protected: char *name; public: virtual Resume* Clone(){return NULL;} virtual void Set(char *n){} virtual void Show(){} }; class ResumeA: public Resume { public: ResumeA(const char *str) { if(str == NULL) { name = new char[1]; name[0] = '\0'; } else { name = new char[strlen(str)+1]; strcpy(name, str); } }//构造函数 ResumeA(const ResumeA &r) { name = new char[strlen(r.name)+1]; strcpy(name, r.name); }//拷贝构造函数 ResumeA* Clone() { return new ResumeA(*this); } void Show() { cout<<"ResumeA name : "<<name<<endl; } }; class ResumeB: public Resume { public: ResumeB(const char *str) { if(str == NULL) { name = new char[1]; name[0] = '\0'; } else { name = new char[strlen(str)+1]; strcpy(name, str); } }//构造函数 ResumeB(const ResumeB &r) { name = new char[strlen(r.name)+1]; strcpy(name, r.name); }//拷贝构造函数 ResumeB* Clone() { return new ResumeB(*this); } void Show() { cout<<"ResumeB name : "<<name<<endl; } }; class ResumeManager { private: vector<Resume *> mResume; public: ResumeManager(){} void add(Resume* resume) { mResume.push_back(resume); } Resume *get(int index) const { assert(index>=0 && index<mResume.size()); return mResume[index]; } }; int main() { ResumeManager *manager = new ResumeManager(); Resume *r1 = new ResumeA("A"); Resume *r2 = new ResumeB("B"); manager->add(r1); manager->add(r2); manager->get(0)->Show(); manager->get(1)->Show(); Resume *r3 = manager->get(0)->Clone(); Resume *r4 = manager->get(1)->Clone(); //删除r1,r2 delete r1; delete r2; r1 = r2 = NULL; //深拷贝所以对r3,r4无影响 r3->Show(); r4->Show(); delete r3; delete r4; r3 = r4 = NULL; }
3)子类转换为父类的方式
《大话设计模式C++版》
#include<iostream> #include <vector> #include <string> using namespace std; //抽象基类 class Prototype { private: string m_strName; public: Prototype(string strName){ m_strName = strName; } Prototype() { m_strName = " "; } void Show() { cout<<m_strName<<endl; } virtual Prototype* Clone() = 0 ; } ; // class ConcretePrototype1 class ConcretePrototype1 : public Prototype { public: ConcretePrototype1(string strName) : Prototype(strName){} ConcretePrototype1(){} virtual Prototype* Clone() { ConcretePrototype1 *p = new ConcretePrototype1() ; *p = *this ; //复制对象 return p ; } } ; // class ConcretePrototype2 class ConcretePrototype2 : public Prototype { public: ConcretePrototype2(string strName) : Prototype(strName){} ConcretePrototype2(){} virtual Prototype* Clone() { ConcretePrototype2 *p = new ConcretePrototype2() ; *p = *this ; //复制对象 return p ; } } ; //客户端 int main() { ConcretePrototype1* test = new ConcretePrototype1("小王"); ConcretePrototype2* test2 = (ConcretePrototype2*)test->Clone(); test->Show(); test2->Show(); return 0; }