“设计模式”学习之三:适配器、装饰模式

一、适配器(Adapter,别名“包装器”Wrapper)

1、引言

假设你手头有一个很好用的第三方库资源(只有接口,无源代码)或者已经有一个独立性比较强的单独工具箱,现在一个项目中面向特定领域的应用中要用到上述资源,可是接口不兼容。这时可以考虑适配器模式,设计适配器(Adaper)将资源类接口(Adaptee)适配成应用中的接口(Target)。

 

2、一般思路

类适配器采用多重继承,图中的“实现继承”是为了与“接口继承”区别,表明子类Adapter只继承其父类Adaptee的实现部分,而不把其接口对外开放。在C++中的public继承既是接口继承又是实现继承。可通过private继承获得实现继承的效果(private继承后,父类中的接口都变为private,当然只能是实现继承)。

客户在Adapter中调用一些操作(如Request()),适配器会调用Adaptee的操作(如SpecificRequest())来实现该请求。

 

3、典型代码

一、类适配器:

(1)在Adapter类声明:

classAdapter : public Target, private Adaptee {… voidRequest(); …}

(2)在Request()实现中,this->SpecificRequest();

二、对象适配器:

(1)在Adapter类声明:

classAdapter : public Target

 {     

   public:

      Adapter(Adaptee*ade);

      voidRequest();

      ……

  private:

     Adaptee*_ade;

}

(2)在构造函数Adapter(Adaptee*ade)实现中,this->_ade = ade;

(3)在Request()实现中,_ade->SpecificRequest();

(4)在客户代码main()中:

  Adaptee*ade = new Adaptee;

  Target*adt = new Adapter(ade);

  adt->Request();

 

4、应用提示

(1)对于对象适配器,允许一个Adapter与多个Adaptee(即Adaptee与它的子类)同时工作。Adapter可一次给所有Adaptee添加功能。

(2)Adapter的工作量取决于Target与Adaptee的相似度。

(3)不同系统对于一个组件Adaptee的接口可能不同,可通过三种途径来实现可插入的Adapter,使组件具有接口适配功能:使用抽象操作;使用代理对象;参数化。

 

二、装饰(Decorator,别名“包装器”Wrapper)

1、引言

当你想为某个对象A而非整个类添加一些功能时,并且不修改A中任何底层代码,可以考虑为这个对象A中嵌入另一个对象B,由B来专门负责装饰。当你需要调用A的某个功能operation()时,只需要创建B(动态,“即付即用”),然后依旧调用operation()即可(当然,你需要让B和A具备同样的接口名称,并在实现中添加特定的装饰内容)。一般,你(客户)不会感觉到装饰前后的差异(透明性),也不会对装饰物B产生任何依赖。

 

2、一般思路

如下图,被装饰对象Component(及其子类)和装饰Decorator(及其子类)有共同的接口operation()。装饰Decorator需要包含一个指向Component对象的指针。

 

3、典型代码

结合《Head first》中的“咖啡”实例,按照上图类的关系,编写实例完整代码如下:

// decorator.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
#include "string"
#include <conio.h>
using namespace std;

class Component
{
public:
	string description;
	Component(){
		description = "unknowed component";
	}
	virtual ~Component(){}
	virtual double Operation() = 0;
	virtual string getDescrition(){
		return description;}
};

class ConcreteComponent1 : public Component
{
public:
	ConcreteComponent1(){
		description = "ConcreteComponent1";
	}
	~ConcreteComponent1(){}
	double Operation(){
		return 1100;
	};
};

class ConcreteComponent2 : public Component
{
public:
	ConcreteComponent2(){
		description = "ConcreteComponent2";
	}
	~ConcreteComponent2(){}
	double Operation(){
		return 2200;
	}
};

class Decorator : public Component
{
public:
	Decorator(Component* com){
		this->_com = com;
	}
	virtual ~Decorator(){
		delete _com;
	}
	double Operation(){return 0;}
protected:
	Component* _com;
};

class ConcreteDecorator1 : public Decorator
{
public:
	ConcreteDecorator1(Component* com):Decorator(com){}
	virtual ~ConcreteDecorator1(){}
	double Operation(){
		return 0.11+_com->Operation();
	};
	string getDescrition(){ 
		return _com->getDescrition()+",ConcreteDecorator1";
	}
};

class ConcreteDecorator2 : public Decorator
{
public:
	ConcreteDecorator2(Component* com):Decorator(com){}
	virtual ~ConcreteDecorator2(){}
	double Operation(){
		return 0.22+_com->Operation();
	}
	string getDescrition(){
		return _com->getDescrition()+",ConcreteDecorator2";
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Component* com1 = new ConcreteComponent1();//产品1
	com1 = new ConcreteDecorator1(com1);
	com1 = new ConcreteDecorator2(com1);
	cout<<com1->getDescrition()<<" == "<<com1->Operation()<<endl;

	Component* com2 = new ConcreteComponent2();//产品2
	com2 = new ConcreteDecorator1(com2);
	com2 = new ConcreteDecorator1(com2);
	com2 = new ConcreteDecorator2(com2);
	com2 = new ConcreteDecorator2(com2);
	cout<<com2->getDescrition()<<" == "<<com2->Operation()<<endl;

	delete com1,com2;
	_getch();/*等待按键继续*/ 
	return 0;
}

(1)在ConcreteDecorator2类的Operation()中 return 0.22+_com->Operation(); 实际相当于书中提到的AddedBehavior(),即在Component类的Operation()(_com-> Operation())基础上增加了操作予以修饰!

(2)在程序_tmain()中,客户只需要知道被修饰对象ConcreteComponent1/2和装饰者ConcreteDecorator1/2的具体名称,调用统一接口Component即可完成操作。

(3)代码运行情况如下:1100+0.22+0.11 = 1100.33; 2200+0.11*2+0.22*2 = 2200.66

 

 

4、应用提示

(1)为使所有装饰对象和Componet对象有相同的接口,需要使用Decorator作为各个装饰对象的父类。当然,你也可以人工去保证接口统一,从而省掉Decorator类。

(2)装饰模式是“改变对象外壳”,今后关注策略Strategy模式用以“改变对象内核”。

(3)装饰模式仅改变对象的职责,而适配器Adapter则为对象提供全新的接口”。

(4)可以将装饰模式视为一个“退化的,仅有一个组件的组合Composite”。

(5)《Head first》引入一个重要的设计原则:“类应该对扩展开放,对修改关闭。”(简称“开放-关闭原则”)。需要把注意力集中在最可能改变的地方,然后应用该原则。

(6)装饰模式的一个负面作用是,需要构建和管理大量的装饰对象。但它们一般是用工厂或生成器来创建(期待实例),会“封装得非常好”,故不用太过担心。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值