【菜鸟学设计】——装饰者模式(Decorator)

情景:

         设想:你女朋友每次出门前都会根据当时的衣着、心情和要到的场合精心挑选一些已有的饰物(如:项链、耳环、手链等)戴上,这些饰物可以任意地混搭,而且不排除以后你女朋友会购入更多的饰物(也就是需求变更)。

         用程序语言描述你女朋友对饰物的佩戴。



解决方案:


1、  采用继承的方式。


类图:

图一


点评:

         使用继承的机制是添加功能(饰物)的一种有效途径,从上层继承过来的类可以被多个子类使用。

         但是这种方式使得GF的装饰佩戴是静态的,GF不能控制对饰物选择的方式和时机。更严重的是,它会导致类的结构层次过多,引起类爆炸。设想,GF购入更多的饰物时,饰物间将随之呈现更多种的组合可能,此时需要引入的类和类层次将爆炸式递增。这不是我们所愿意看到的。

          

2、  利用布尔变量标识。


类图:

图二


点评:

         用一个布尔值标识一种饰物,“真”标识佩戴该饰物,“假”标识未佩戴。

         这种结构只需要一个类,避免了类层次和类数目爆炸增长的问题。但是,每当GF购买多一种饰物时,需要添加标识该饰物的布尔变量、添加Set*()和Has*()方法以及Show()方法也需要改动。

这种方式显然违背了类对扩展开放,对修改关闭的设计原则。

注:

         类对扩展开放,对修改关闭:一般我们设计的目标应该在不修改现有代码的前提下,可以容易地添加新的行为(即扩展)。因为现有的代码可能是花了很多时间不断修改后才得到的正确代码,对其修改容易引人新的bug。

 

3、  采用装饰者模式。


类图:

图三


点评:

         符合多用组合,少用继承的设计原则。而且此处的继承目的并不是为了获得父类的行为能力,而是为了使得GF和Ornament达到类型匹配

         这种方式使得GF和Ornament子类可以更有弹性地混合,而且Ornament的混合配搭可以在运行时决定,GF可以控制对饰物选择的时机。

         符合类对扩展开放,对修改关闭的设计原则,GF购买一种新的饰物时,只要针对新购饰物继承自Ornament类即可,对原有的代码不需要做任何更改。

 


意图:

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

 

适用性:


1、  只希望给某个对象而不是整个类添加一些功能(装饰)时。

2、  希望可以选择时机动态地为某对象添加功能(装饰)。

3、  当不能使用继承的方式来扩展时。一种情况是,有大量独立的扩展,为支持每一种扩展的组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况是,类的定义被隐藏,或类定义不能用于生成子类。

 


模式框架:

图四

 


参与者职责:

Component(Component):定义一个接口,使得饰物(功能)和被装饰者拥有同样的类型。

Decorator(Ornament):饰物(功能),内含一个指向Component对象的指针。

Concrete Decorator(Necklace、earings、bracelet):具体饰物(功能),可以向被装饰者添加饰物(功能)。

ConcreteComponent(GF):被装饰者,可以给被装饰者添加饰物(功能)。

 


参与者协作:

Decorator把请求转发给它的Component对象,并可能在转发前后执行一些附加的操作。

 


示例代码:

 

#include <iostream>
using namespace std;

class Component
{
public:
	virtual ~Component() {}
	virtual void Show() = 0;
};

class GF : public Component
{
public:
	void Show()
	{
		cout<<"GF  adorn :  ";
	}
};

class Ornament : public Component
{
public:
	Ornament(Component* pComponent)	
	{
		m_pComponent = pComponent; 
	}

	~Ornament()	
	{ 
		delete(m_pComponent); 
	}

	virtual void Show() = 0;

protected:
	Component* m_pComponent;
};

class Necklace : public Ornament
{
public:
	Necklace(Component* pComponent) : Ornament(pComponent)	{}

	void Show()
	{
		m_pComponent->Show();
		cout<<"Necklace  ";
	}
};

class Earings : public Ornament
{
public:
	Earings(Component* pComponent) : Ornament(pComponent){}

	void Show()
	{
		m_pComponent->Show();
		cout<<"Earings  ";
	}
};

class Bracelet : public Ornament
{
public:
	Bracelet(Component* pComponent) : Ornament(pComponent){}

	void Show()
	{
		m_pComponent->Show();
		cout<<"Bracelet  ";
	}
};

int main()
{
	Component* pGf = new GF();
	pGf = new Bracelet(pGf);
	pGf = new Earings(pGf);
	pGf = new Necklace(pGf);
	pGf->Show();

	delete pGf;

	getchar();
	return 0;
}


总结:

         相较于对象的继承,显然Decorator模式提供了更灵活的方式向对象添加功能(装饰),它可以在运行时刻添加或减少对象的功能,同时避免了过多的类层次和爆炸性的类数目增长。



参考资料:

【GoF设计模式】

【Head First 设计模式】


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值