按照设计模式书上的介绍:
意图:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
适用性:
当一个系统应该独立于他的产品创建、构成和表示时,需要使用原型模式
当要实例化的类是在运行时刻指定时,如通过动态装载
为了避免创建一个与产品类层次平行的工厂类层次时
当一个类的实例只能有几个不同状态组合中的一种时,建立相应数目的原型并克隆他们可能比每次用合适的状态手工实例化该类更方便一些。
意义:
Prototype 的意义在于,你拿到一个 Base* ,它指向某个 Derived 对象,你想克隆出 Derived 对象,但代码中不写出 Derived 的具体类型,因为有很多派生类,这种情况下你用构造函数是搞不定的,type-switch 是 bad smells 。
另外,这里考虑 virtual 的性能损失是主次不分,构造对象需要分配内存,这开销比一次虚函数调用大多了。
Prorobuf Message 就采用了 prototype 模式,你可以参考一下。我们先给一个通用的架构例子:
prototype.h
//设计模式之原型模式 /* 解析: Prototype模式其实就是常说的"虚拟构造函数"一个实现,C++的实现机制中并没有支持这个特性, 但是通过不同派生类实现的Clone接口函数可以完成与"虚拟构造函数"同样的效果.举一个例子来 解释这个模式的作用,假设有一家店铺是配钥匙的,他对外提供配制钥匙的服务(提供Clone接口函 数),你需要配什么钥匙它不知道只是提供这种服务,具体需要配什么钥匙只有到了真正看到钥匙 的原型才能配好.也就是说,需要一个提供这个服务的对象,同时还需要一个原型(Prototype),不 然不知道该配什么样的钥匙. */ //声明一个虚拟基类,所有的原型都从这个基类继承, class prototype { public: prototype(){} virtual ~prototype(){} virtual prototype* clone() = 0;//纯虚函数,需要供继承者自行实现 }; // 派生自Prototype,实现Clone方法 class concreateprototype1:public prototype { public: concreateprototype1(); concreateprototype1(const concreateprototype1&); virtual ~concreateprototype1(); virtual prototype* clone(); }; // 派生自Prototype,实现Clone方法 class concreateprototype2:public prototype { public: concreateprototype2(); concreateprototype2(const concreateprototype2&); virtual ~concreateprototype2(); virtual prototype* clone(); };
prototype.cpp
#include "prototype.h" #include <iostream> using namespace std; concreateprototype1::concreateprototype1() { cout<<"concreteprototype1 create"<<endl; } concreateprototype1::concreateprototype1(const concreateprototype1 &contype ) { cout<<"copy the concreteprototype1"<<endl; } concreateprototype1::~concreateprototype1() { cout<<"destruction of concreteprototype1"<<endl; } prototype* concreateprototype1::clone() { return new concreateprototype1(*this); } concreateprototype2::concreateprototype2() { cout<<"concreteprototype2 create"<<endl; } concreateprototype2::concreateprototype2(const concreateprototype2 &contype ) { cout<<"copy the concreteprototype2"<<endl; } concreateprototype2::~concreateprototype2() { cout<<"destruction of concreteprototype2"<<endl; } prototype* concreateprototype2::clone() { return new concreateprototype2(*this); }
使用的时候可以这么使用:
prototype *ptype1 = new concreateprototype1(); prototype *copytype1 = ptype1->clone(); delete ptype1; delete copytype1;
找工作的时候,我们需要准备简历。假设没有打印设备,因此需手写简历,这些简历的内容都是一样的。这样有个缺陷,如果要修改简历中的某项,那么所有已写好的简历都要修改,工作量很大。随着科技的进步,出现了打印设备。我们只需手写一份,然后利用打印设备复印多份即可。如果要修改简历中的某项,那么修改原始的版本就可以了,然后再复印。原始的那份手写稿相当于是一个原型,有了它,就可以通过复印(拷贝)创造出更多的新简历。
resume.h
//首先抽象一个基类 class resume { protected: char *name; public: resume() { } virtual ~resume() { } virtual void set(const char *str) { } virtual void show() { } virtual resume* clone() { return 0; } }; class ResumeA : public resume { public: ResumeA(const char *str); //构造函数 ResumeA(const ResumeA &r); //拷贝构造函数 ~ResumeA(); //析构函数 ResumeA* clone(); //克隆,关键所在 void show(); //显示内容 }; class ResumeB : public resume { public: ResumeB(const char *str); //构造函数 ResumeB(const ResumeB &r); //拷贝构造函数 ~ResumeB(); //析构函数 ResumeB* clone(); //克隆,关键所在 void show(); //显示内容 };
resume.cpp
#include "resume.h" #include <iostream> using namespace std; ResumeA::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::~ResumeA() { delete [] name;} ResumeA::ResumeA(const ResumeA &r) { name = new char[strlen(r.name)+1]; strcpy(name, r.name); } ResumeA* ResumeA::clone() { return new ResumeA(*this); } void ResumeA::show() { cout<<"ResumeA name : "<<name<<endl; } ResumeB::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::~ResumeB() { delete [] name;} ResumeB::ResumeB(const ResumeB &r) { name = new char[strlen(r.name)+1]; strcpy(name, r.name); } ResumeB* ResumeB::clone() { return new ResumeB(*this); } void ResumeB::show() { cout<<"ResumeB name : "<<name<<endl; } int main() { resume *r1 = new ResumeA("A"); resume *r2 = new ResumeB("B"); resume *r3 = r1->clone(); resume *r4 = r2->clone(); r1->show(); r2->show(); //删除r1,r2 delete r1; delete r2; r1 = r2 = NULL; //深拷贝所以对r3,r4无影响 r3->show(); r4->show(); delete r3; delete r4; r3 = r4 = NULL; }
其实这个设计模式比较简单,我们总结一下具体操作步骤。
1、声明一个抽象基类,并定义clone()函数为纯虚函数。
2、实例化各个子类,并且实现复制构造函数,并实现clone()函数