迭代器模式(转自http://www.shenmiguo.com/archives/2009/296_design-patterns-adapter.html)
定义:将一个类的接口转换成客户希望的另外一个接口。适配器(Adapter)模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。也叫包装器(Wrappter)。
结构
对象适配器(Object Adapter
),使用对象组合方式:
![对象适配器 对象适配器](http://www.shenmiguo.com/wp-content/uploads/2009/08/adapter-composite.jpg)
类适配器(Class Adapter
),使用类继承方式:
![类适配器 类适配器](http://www.shenmiguo.com/wp-content/uploads/2009/08/adapter-derived.jpg)
要点
1.
适配器模式适用于:
你想使用一个已经存在的类,而它的接口不符合你的需求。
你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
(仅适用于对象适配器)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
2.
C++
使用类适配器时
,Adapter
类使用public
方式继承Target
类,并使用private
方式继承Adaptee
类。这样,Adapter
是Target
子类型,但不是Adaptee
子类型。如此这般,推荐使用对象适配器方式。
3.
适配器模式与桥接(
Bridge
)模式的区别
。桥接模式的目的是将接口部分与实现分离,从而使它们能相对独立的改变;桥接是设计阶段行为。适配器模式是对已有接口的改变,使得功能相同但接口不兼容的类桥接在一起。
应用
在中国大陆,使用中式插座(CCnOutlet
)。买了一个水货手机,但充电器使用英式插座(CEnOutlet
)。要想在中式插座上给手机充电,就得买一个插座转换器(CCnOutletAdapter
)来,使两个不匹配的接口可以正常工作。插座转换器就是适配器(Adapter
),英式插座是适配者(Adaptee
)。
源码中使用对象适配器方式,这样的好处是,适配器可以有多个适配者,譬如我要兼容美式插座,只需要新增
美式
插座CUsOutlet
,并且将CUsOutlet
作为CCnOutletAdapter
的成员即可。
***CnOutlet.h***
#ifndef CNOUTLET_H
#define CNOUTLET_H
class CnOutlet{
public :
virtual ~ CnOutlet();
virtual void CnPlug();
protected :
CnOutlet();
};
#endif
#define CNOUTLET_H
class CnOutlet{
public :
virtual ~ CnOutlet();
virtual void CnPlug();
protected :
CnOutlet();
};
#endif
***EnOutlet.h***
#ifndef ENOUTLET_H
#define ENOUTLET_H
class EnOutlet{
public :
EnOutlet();
virtual ~ EnOutlet();
virtual void Enplug();
};
#endif
#define ENOUTLET_H
class EnOutlet{
public :
EnOutlet();
virtual ~ EnOutlet();
virtual void Enplug();
};
#endif
***Adapter.h****
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#ifndef ADAPTER_H
#define ADAPTER_H
#include " CnOutlet.h "
#include " EnOutlet.h "
class CnOutletAdapter: public CnOutlet{
public :
CnOutletAdapter();
CnOutletAdapter(EnOutlet * );
virtual ~ CnOutletAdapter();
virtual void CnPlug();
private :
EnOutlet * m_enoutlet;
};
#endif
#define ADAPTER_H
#include " CnOutlet.h "
#include " EnOutlet.h "
class CnOutletAdapter: public CnOutlet{
public :
CnOutletAdapter();
CnOutletAdapter(EnOutlet * );
virtual ~ CnOutletAdapter();
virtual void CnPlug();
private :
EnOutlet * m_enoutlet;
};
#endif
***CnOutlet.cpp***
#include
<
iostream
>
#include " CnOutlet.h "
using namespace std;
CnOutlet::CnOutlet(){}
CnOutlet:: ~ CnOutlet(){}
void CnOutlet::CnPlug(){
cout << " 使用中式插座 " << endl;
}
#include " CnOutlet.h "
using namespace std;
CnOutlet::CnOutlet(){}
CnOutlet:: ~ CnOutlet(){}
void CnOutlet::CnPlug(){
cout << " 使用中式插座 " << endl;
}
***EnOutlet.cpp***
#include
<
iostream
>
// #include "EnOutlet.h"
#include " EnOutlet.h "
using namespace std;
EnOutlet::EnOutlet(){}
EnOutlet:: ~ EnOutlet(){}
void EnOutlet::Enplug(){
cout << " 使用英式插座 " << endl;
}
// #include "EnOutlet.h"
#include " EnOutlet.h "
using namespace std;
EnOutlet::EnOutlet(){}
EnOutlet:: ~ EnOutlet(){}
void EnOutlet::Enplug(){
cout << " 使用英式插座 " << endl;
}
***Adapter.cpp***
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
iostream
>
#include " Adapter.h "
using namespace std;
CnOutletAdapter::CnOutletAdapter(){m_enoutlet = NULL;}
CnOutletAdapter::CnOutletAdapter(EnOutlet * p):m_enoutlet(p)
{
}
CnOutletAdapter:: ~ CnOutletAdapter(){
if (m_enoutlet)
delete m_enoutlet;
}
void CnOutletAdapter::CnPlug(){
if (m_enoutlet != NULL)
{
cout << " 使用适配器进行转化 " << endl;
m_enoutlet -> Enplug();
}
else
{
CnOutlet::CnPlug();
}
}
#include " Adapter.h "
using namespace std;
CnOutletAdapter::CnOutletAdapter(){m_enoutlet = NULL;}
CnOutletAdapter::CnOutletAdapter(EnOutlet * p):m_enoutlet(p)
{
}
CnOutletAdapter:: ~ CnOutletAdapter(){
if (m_enoutlet)
delete m_enoutlet;
}
void CnOutletAdapter::CnPlug(){
if (m_enoutlet != NULL)
{
cout << " 使用适配器进行转化 " << endl;
m_enoutlet -> Enplug();
}
else
{
CnOutlet::CnPlug();
}
}
***main.cpp***
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
iostream
>
#include " Adapter.h "
using namespace std;
void main( void )
{
CnOutlet * cnoutlet;
cnoutlet = new CnOutletAdapter();
cnoutlet -> CnPlug();
delete cnoutlet;
EnOutlet * enoutlet = new EnOutlet;
cnoutlet = new CnOutletAdapter(enoutlet);
cnoutlet -> CnPlug();
}
#include " Adapter.h "
using namespace std;
void main( void )
{
CnOutlet * cnoutlet;
cnoutlet = new CnOutletAdapter();
cnoutlet -> CnPlug();
delete cnoutlet;
EnOutlet * enoutlet = new EnOutlet;
cnoutlet = new CnOutletAdapter(enoutlet);
cnoutlet -> CnPlug();
}
【优点】使用适配器模式,可以将一个系统的接口和本来不相容的另一个系统的类联系起来,从而使得这两个类能够在一起工作,强调了对接口的转换。
【缺点】对于类适配器来说,不能适配一个类以及它的子类;对于对象适配器来说,重新定义被适配的类的行为比较困难。