设计模式-原型模式

这次我们来讲一下原型模式。总体来讲原型模式还是比较简单的。

 

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

 

结构图

这个结构图还是挺简单的,Prototype就是产品类。

和前面的抽象工厂,工厂方法等模式相比,产品类就增加了一个函数Clone()。

我们还是以之前的地形例子来讲解这个模式,先给出类图

我这次把CFactory当作原型模式的client。

先看看产品类的实现:

class CComponent
{
public:
	virtual void LoadPicture() = 0;
	virtual CComponent* Clone() = 0;
};


class CSnowBackground: public CComponent
{
public:
	virtual void LoadPicture()
	{
		std::cout<< "Load snow background picture \n"; 
	}

	virtual CComponent* Clone()
	{
		CComponent* clone = new CSnowBackground();
		return clone;
	}
};

class CSnowGround: public CComponent
{
public:
	virtual void LoadPicture()
	{
		std::cout<< "Load snow ground picture\n"; 
	}

	virtual CComponent* Clone()
	{
		CComponent* clone = new CSnowGround();
		return clone;
	}
};


跟之前抽象工厂模式对比,这次我们只是增加了一个函数Clone(),然后实现它。

这个例子的Clone里面,我只是创造了一个新的空对象,假如当前类有一些属性的话,那么我们可以在Clone里面把当前对象的属性复制给新创建的对象。

看看client类CFactory的实现:

class CFactory
{
public:
	//生产一个Terrain对象
	virtual CTerrain* MakeTerrain()
	{
		return new CTerrain();
	}
	virtual CComponent* MakeBackground() = 0;
	virtual CComponent* MakeGround() = 0;

	//生产一个天气对象
	virtual CWeather* MakeWeather() = 0;
};

class CProtoFactory: public CFactory
{
public:
	CProtoFactory(CComponent* bg, CComponent* gr)
	{
		m_bg = bg;
		m_gr = gr;
	}

	virtual CComponent* MakeBackground()
	{
		return m_bg->Clone();
	}
	virtual CComponent* MakeGround()
	{
		return m_gr->Clone();
	}


private:
	CComponent* m_bg;
	CComponent* m_gr;	
};


 

CFactory还是没有变。然后我把CFactory的子类改变了一下:

1. 去掉了singleton;

2. 增加了2个数据成员,背景实例和地面实例;

3. 然后在构造函数里面增加了2个参数。

4. 在MakeBackground和MakeGround里面不再调用产品类的构造函数,取而代之的是调用产品类的Clone函数。

 

再看看CCreator类的实现,跟抽象工厂模式几乎没有分别,(这里为了简单化,我去掉了天气对象的创建)

class CCreator
{
public:
	void Create(CFactory& factory, CTerrain** t)
	{
		CTerrain* terrain = factory.MakeTerrain();
		CComponent* bg = factory.MakeBackground();
		CComponent* ground = factory.MakeGround();

		bg->LoadPicture();
		ground->LoadPicture();
		terrain->SetBackground(bg);
		terrain->SetGround(ground);

		*t = terrain;
	}
};


 

那么客户端怎么调用呢,看下面代码:

CComponent* bg = new CSnowBackground();
CComponent* gr = new CSnowGround();
CProtoFactory factory(bg, gr);

CCreator creator;
CTerrain* terrain = NULL;
creator.Create(factory, &terrain);//这里就得到了以前面的2个原型创建出来的地形实例

关键在于前面2行定义的2个原型,这2个原型被传递到了工厂实例里面,从而使得工厂可以生产以这2个实例为原型的产品。

假如我们拿原型模式和抽象工厂模式相比,我们会发现,对于抽象工厂模式,每增加一些新产品系列,就得相应的增加子工厂类。

而原型模式,就不需要增加新的子工厂类,只要指定原型就好了,比如我们现在要创建森林地形。那么可以这么做。

CComponent* bg = new CForestBackground();
CComponent* gr = new CForestGround();
CProtoFactory factory(bg, gr);

CCreator creator;
CTerrain* terrain = NULL;
creator.Create(factory, &terrain);//这里就得到了森林地形实例

跟前面的代码相比较,唯一的区别就是原型不同,其他一样。

好了,原型模式就基本介绍完了。

其实总体来讲原型模式还是蛮简单的,我觉得里面的关键应该就是Clone函数怎么实现了。

如果一个类很简单,那么Clone函数也很容易实现,但是如果一个类的数据成员比较复杂,里面有成员不支持拷贝或者有循环引用等等,这个时候实现Clone函数就比较困难了。

 

做过C#和JAVA的朋友会发现,其实,C#和JAVA里面本身就可以支持原型模式了。

C#和JAVA 都有反射机制。也就是说可以在运行的时候从一个变量上面获取变量类型的信息,我们称之为类对象,这个类对象里面包含了很多类型信息,比如数据成员,成员函数等等。而且可以从类对象来创建新的实例。那么对于C#和JAVA来说基本就不需要原型模式了。因为类对象就是原型。原型模式对于C++来说还是有一定作用的。



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值