原型模式,如其名称,核心就是要实现一个原型类,该类支持clone操作,从而客户可以从原型克隆出具体的类。
其效果主要有如下:
可以动态增加和删除产品。这个就是通过clone代替new等操作,也避免了客户与具体类打交道。
通过改变对象的值,指定新的对象。clone出一个新对象后可以修改其参数改变对象,如果参数较多,可以提供类似initialize方法。
减少creator类,减少子类数目。客户看起来直接从一个原型克隆出一个新的对象,而不是跟工厂方法打交道,因而少了一个类层次。
动态配置应用,这个真是没想明白。也没个例子,我想大致意思就是将原型编译成动态库等,初始化阶段构造原型对象,运行时从原型克隆出新的类吧。
写了个简单demo,供参考:
/**
* @file test_prototype.cpp
* @author itegel
* @date 2013/09/18 15:15:26
* @brief
*
**/
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Prototype{
public:
Prototype(){_myself = "Prototype";}
~Prototype(){}
void ShowMyself(){
cout<<"I am "<<_myself<<endl;
}
void SetMyself(string str){
_myself = str;
}
virtual Prototype * Clone() = 0;
private:
string _myself;
};
//Colour prototype for all colours
class Colour:public Prototype{
public:
Colour(){
SetRGB(0,0,0);
SetMyself("Colour");
}
~Colour(){}
void SetRGB(int r, int g, int b){
_R = r;
_G = g;
_B = b;
}
int GetR() const {return _R;}
int GetG() const {return _G;}
int GetB() const {return _B;}
void Print(){
cout<<"R:G:B=>"<<_R<<":"<<_G<<":"<<_B<<endl;
}
Colour(const Colour& other){
this->SetRGB(other.GetR(),other.GetG(), other.GetB());
}
virtual Colour * Clone(){
return new Colour(*this);
}
private:
int _R;
int _G;
int _B;
};
//Type prototype for all colours
class Type:public Prototype{
public:
Type(){
SetTypeStr("0,0;");
SetMyself("Type");
}
~Type(){}
void SetTypeStr(string type){
_type_str = type;
}
string GetTypeStr() const{return _type_str;}
void Print(){
cout<<"type:"<<_type_str<<endl;
}
Type(const Type& other){
this->SetTypeStr(other.GetTypeStr());
}
virtual Type * Clone(){
return new Type(*this);
}
private:
string _type_str;
};
class PrototypeMapManager{
public:
PrototypeMapManager(){}
~PrototypeMapManager(){}
int RegisterPrototype(string name, Prototype * prototype){
map<string, Prototype *>::iterator iter = _prototype_map.find(name);
if (iter != _prototype_map.end()){
cout<<"prototype["<<name<<"] already exist!"<<endl;
return -1;
}
_prototype_map.insert(pair<string, Prototype *>(name, prototype));
return 0;
}
Prototype * GetPrototype(string name){
map<string, Prototype *>::iterator iter = _prototype_map.find(name);
if (iter == _prototype_map.end()){
cout<<"prototype["<<name<<"] not find!"<<endl;
return NULL;
} else {
return iter->second;
}
}
private:
map<string, Prototype *> _prototype_map;
};
//client
int main(){
//test simple prototype
Colour * prototype = new Colour();
cout<<"1. prototype:"<<endl;
prototype->Print();
Colour * blue = prototype->Clone();
cout<<"2. after cloned:"<<endl;
blue->Print();
blue->SetRGB(0,0,255);
cout<<"3. after set property:"<<endl;
blue->Print();
delete prototype;
Type * type_prototype = new Type();
Type * line = type_prototype->Clone();
line->SetTypeStr("0,0;99,99;");
cout<<"4. line:"<<endl;
line->Print();
//test dynamic produce objects
cout<<endl;
cout<<"DYNAMIC produce TEST"<<endl;
PrototypeMapManager ProtoMgr;
Colour * colour_prototype = new Colour();
ProtoMgr.RegisterPrototype("Colour", colour_prototype);
blue->SetMyself("Blue");
ProtoMgr.RegisterPrototype("Blue", blue);
ProtoMgr.RegisterPrototype("Type", type_prototype);
line->SetMyself("Line");
ProtoMgr.RegisterPrototype("Line", line);
Prototype * clr_proto = ProtoMgr.GetPrototype("Colour");
clr_proto->ShowMyself();
Prototype * blue_proto = ProtoMgr.GetPrototype("Blue");
blue_proto->ShowMyself();
Prototype * red_proto = blue_proto->Clone();
red_proto->SetMyself("Red");
red_proto->ShowMyself();
Prototype * line_proto = ProtoMgr.GetPrototype("Line");
line_proto->ShowMyself();
return 0;
}
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
执行结果如下:
1. prototype:
R:G:B=>0:0:0
2. after cloned:
R:G:B=>0:0:0
3. after set property:
R:G:B=>0:0:255
4. line:
type:0,0;99,99;
DYNAMIC produce TEST
I am Colour
I am Blue
I am Red
I am Line
prototype比较麻烦的一点就是clone操作的定义有时候不是那么容易的。涉及到深浅拷贝等问题。具体网上有很多讨论,这里就不抄袭了。对于简单类这个其实也不是什么困难事。