3.4Prototype

意图:

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。这个其实和C++的拷贝构造函数的作用是一致的,实际上就是动态抽取当前对象运行时的状态。

 

UML图:

3.4Prototype_第1张图片

客户(Client)角色:让一个原型克隆自身从而创建一个新的对象。

抽象原型(Prototype)角色:这是一个抽象角色,抽象类实现。此角色声明一个克隆自身的接口。

具体原型(Concrete Prototype)角色:实现一个克隆自身的操作。

 

适用性

1.当一个系统应该独立于它的产品创建、构成和表示时;

2.当要实例化的类是在运行时指定时(如动态装载);

3.为了避免创建一个与产品类层次平行的工厂类层次时;

4.当一个类的实例只能有几个不同状态组合中的一种时。

 

例子:

//prototype抽象类,定义了Clone接口
#ifndef _RESUME_H
#define _RESUME_H

#include <iostream>
class Resume
{
protected:
	char *name;
public:
	Resume(){}
	virtual ~Resume(){}
	virtual Resume *Clone()
	{
		return NULL;
	}
	virtual void Show(){}
};
#endif

//ConcretePrototype,实现了Clone接口
#ifndef _RESUME_A_H
#define _RESUME_A_H

#include "Resume.h"
#include <iostream>
using namespace std;

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()
	{
		delete[] name;
	}

	ResumeA(const ResumeA &r)
	{
		name = new char[strlen(r.name)+1];
		strcpy(name, r.name);
	}

	virtual Resume* Clone()
	{
		return new ResumeA(*this);
	}

	virtual void Show()
	{
		cout<<"ResumeA:"<<name<<endl;
	}
};
#endif

//ConcretePrototype,实现了Clone接口
#ifndef _RESUME_B_H
#define _RESUME_B_H

#include "Resume.h"
#include <iostream>
using namespace std;

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()
	{
		delete[] name;
	}

	ResumeB(const ResumeB &r)
	{
		name = new char[strlen(r.name)+1];
		strcpy(name, r.name);
	}

	virtual Resume* Clone()
	{
		return new ResumeB(*this);
	}

	virtual void Show()
	{
		cout<<"ResumeB:"<<name<<endl;
	}
};
#endif

//Client
#include "Resume.h"
#include "ResumeA.h"
#include "ResumeB.h"

int main(int argc, char **argv)
{
	Resume *r1 = new ResumeA("AAAAA");
	Resume *r2 = new ResumeB("BBBBB");

	Resume *r3 = r1->Clone();
	Resume *r4 = r2->Clone();

	delete r1;
	r1 = NULL;
	delete r2;
	r2 = NULL;

	r3->Show();
	r4->Show();

	system("pause");
	return 0;
}

带Prototype Manager的原型模式:

当系统中的原型数目不固定时(也就是说,它们可以动态创建和销毁),要保持一个可用原型的注册表。客户不会自己来管理原型,但会在注册表中存储和检索原型。

3.4Prototype_第2张图片

原型管理器(PrototypeManager)角色:创建具体原型类的对象,并记录每一个被创建的对象。


例子:

//Prototype Manager,有一个Add,一个Get
#ifndef _RESUME_MANAGER_H
#define _RESUME_MANAGER_H

#include "Resume.h"
#include <vector>
using namespace std;
class ResumeManager
{
private:
	vector<Resume*> mResume;
public:
	ResumeManager(){}
	~ResumeManager(){}
	void AddResume(Resume *resume)
	{
		mResume.push_back(resume);
	}
	Resume *GetIndex(int index)
	{
		if(index>=0 && index<mResume.size())
			return mResume[index];
		else
			return NULL;
	}
};
#endif

//Client
#include "Resume.h"
#include "ResumeA.h"
#include "ResumeB.h"
#include "ResumeManager.h"

int main(int argc, char **argv)
{
	ResumeManager *rManager = new ResumeManager();

	Resume *r1 = new ResumeA("AAAAA");
	Resume *r2 = new ResumeB("BBBBB");
	rManager->AddResume(r1);
	rManager->AddResume(r2);
	rManager->GetIndex(0)->Show();
	rManager->GetIndex(1)->Show();

	Resume *r3 = rManager->GetIndex(0)->Clone();
	Resume *r4 = rManager->GetIndex(1)->Clone();

	delete r1;
	r1 = NULL;
	delete r2;
	r2 = NULL;

	r3->Show();
	r4->Show();
	delete r3;
	delete r4;
	r3 = r4 = NULL;

	system("pause");
	return 0;
}

Prototype模式的主要缺陷是每个Prototype子类都必须实现Clone操作。这很困难。比如考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者右循环引用的对象时,实现Clone也可能会很困难。

PS:注意深拷贝和浅拷贝。



你可能感兴趣的:(设计模式,prototype)