定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。不用重新初始化对象,而是动态的获得对象运行时的状态。
适用性:
当一个系统应该独立于它的产品创建、构成和表示时,用使用Prototype模式,以及
1 当要实例话的类是在运行时刻指定时,例如,动态装载
2 为了避免创建一个与产品类层次平行的工厂类层次时(这是抽象工厂与工厂模式)
3 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆他们比每次用合适的状态手工实例化该类更方便一些。
结构:
参与者:
Prototype:声明一个克隆自身的接口
ConcretePrototype:实现一个克隆自身的操作
Client:让一个原型克隆自身从而创建一个新的对象
协作:
客户请求原型克隆自身
效果:与抽象工厂,建造者一样的效果:对客户端隐藏了具体的产品类,因而减少了客户知道的名字的数目,使客户无需改变就棵使用与特定应用相关的类
其他优点:
1 可以在运行时刻增加和删除产品。比其他创建型模式更灵活,因为客户可以在运行时刻建立和删除原型。
2 改变值以指定新对象。事实上,克隆一个原型类似于实例化一个类,原型模式可以极大的减少系统所需要的类的数目
3 改变结构以指定新对象
4 减少子类的构造:工厂方法每个对象都需要一个工厂方法,这些对原型都不需要。工厂方法产生一个与产品类层次平行的Creator类层次,原型模式使得克隆一个原型而不是请求一个工厂方法去产生一个新的对象,所以根本不需要Creator类层次。这个优点主要适用于像C++一样不将类作为一级类对象的语言。
5 用类动态配置应用,一些运行时刻环境允许动态将类加载到应用中,c++中,原型模式是利用这种功能的关键。
主要缺陷:每个Prototype的子类都必须实现Clone操作,这可能比较困难,例如,当所考虑的类已经存在时就难以新增clone操作,当内部包括一些不支持拷贝或有循环引用的对象时,实现可能比较困难。
实现:
1 使用一个原型管理器
2 实现克隆操作
按照自己的理解:一个原型基类,有一个clone虚函数,n个原型实例继承自基类,每个也有一个clone。而C++的原型实现借助拷贝构造函数,clone函数中调用拷贝构造函数,实现自身的一个拷贝, new class(*this),需要注意的是带有指针的类,会有浅拷贝和深拷贝之分,这个模式下指深拷贝,将指针所指的内容一起拷贝,而不是指向同一块内存。
3 初始化克隆对象:当客户希望使用一些值初始化该对象的一些或所有的内部状态时,一般说来不可能在clone操作中传递这些值,因为这些值的书目由于原型的类的不同而不同,在clone操作中传递参数会破坏克隆接口的统一性。可以引入一个initialize操作,该操作使用初始化参数设定克隆对象的内部状态。
模式适用于具有复杂属性的类,调用clone比直接用构造函数节省开销(是的吗。。不是特别清楚)
以下按照大话设计模式第9章 原型模式的例子:
//原型模式:用原型实例指定创建对象的种类,
//并且通过拷贝这些原型创建新的对象
//c++的原型模式借助拷贝构造函数实现,对象的构造不是通过构造函数,
//而是通过一个clone函数完成,而这个函数中调用拷贝构造函数,实现自身的拷贝
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
//原型基类
class ICloneable
{
protected:
virtual ICloneable* Clone() = 0;
};
//具体原型类
class WorkExperience : public ICloneable
{
public:
WorkExperience() : workDate(""), company("")
{
}
WorkExperience(string _workDate, string _company)
: workDate(_workDate), company(_company)
{
}
WorkExperience(const WorkExperience& object)
{
workDate = object.workDate;
company = object.company;
}
ICloneable* Clone()
{
cout << "clone一个WorkExperience" << endl;
//调用拷贝构造函数实现clone
return new WorkExperience(*this);
}
//private:
string workDate;
string company;
};
//原型具体类
class Resume : public ICloneable
{
public:
Resume(string _name) : name(_name), sex(""), age(0), work(new WorkExperience)
{
}
Resume(const Resume& object)
{
work = (WorkExperience*)(object.work->Clone());
name = object.name;
sex = object.sex;
age = object.age;
}
~Resume()
{
delete work;
work = NULL;
}
//设置个人信息
void SetPersonalInfo(string _sex, int _age)
{
sex = _sex;
age = _age;
}
//设置个人经历
void SetWorkExperience(string _workdate, string _company)
{
work->workDate = _workdate;
work->company = _company;
}
ICloneable* Clone()
{
cout << "\nclone一份简历...." << endl;
return new Resume(*this);
}
void Display()
{
cout << name << " " << sex << " " << age << endl;
cout << "工作经历: " << work->workDate << " " << work->company << endl;
}
private:
string name;
string sex;
int age;
WorkExperience *work;
};
int main()
{
Resume *a = new Resume("大鸟");
a->SetPersonalInfo("男", 29);
a->SetWorkExperience("1999-2000", "XX公司");
a->Display();
//运用clone加更改
Resume *b = (Resume*)(a->Clone());
b->SetWorkExperience("1998-2006", "YY企业");
b->Display();
Resume *c = (Resume*)a->Clone();
c->SetPersonalInfo("女", 23);
c->SetWorkExperience("1998-2003", "ZZ企业");
c->Display();
delete a;
a = NULL;
delete b;
b = NULL;
delete c;
c = NULL;
system("pause");
return 0;
}
运行结果: