定义
将一个类的接口转换成客户希望的另外一个接口。适配器(Adapter
)模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。也叫包装器(
Wrappter
)。
结构
对象适配器(Object Adapter
),使用对象组合方式:
类适配器(Class Adapter
),使用类继承方式:
理解
1. Target
是供Client
调用的抽象基类。
2. Adaptee
是需要适配的类(适配者类)。Adaptee
的方法(SpecificRequest
)与Target
的方法(Request
)是不兼容的。
3. Adapter
是适配器类。完成对Target
和Adaptee
的接口适配工作。Adapter
重新实现Request
方法,内部隐藏了调用Adaptee
不兼容方法(SpecificRequest
)的细节。
4.
类适配器
是通过继承类适配者类(Adaptee
)实现的。类适配器实现客户类所需要的方法(SpecificRequest
)。当客户对象调用适配器类(Adapter
)方法的时候,适配器内部调用它所继承的适配者的方法。
5.
对象适配器
包含一个适配器者的引用,与类适配器相同,对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。对象组合方式,允许一个Adapter
适配多个Adaptee
。
要点
1.
适配器模式适用于:
你想使用一个已经存在的类,而它的接口不符合你的需求。
你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
(仅适用于对象适配器)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
2.
C++
使用类适配器时
,
Adapter类使用public方式继承Target类,并使用private方式继承Adaptee
类。这样,Adapter
是Target
子类型,但不是Adaptee
子类型。如此这般,推荐使用对象适配器方式。
3.
适配器模式与桥接(
Bridge
)模式的区别
。桥接模式的目的是将接口部分与实现分离,从而使它们能相对独立的改变;桥接是设计阶段行为。适配器模式是对已有接口的改变,使得功能相同但接口不兼容的类桥接在一起。
应用
在中国大陆,使用中式插座(CCnOutlet
)。买了一个水货手机,但充电器使用英式插座(CEnOutlet
)。要想在中式插座上给手机充电,就得买一个插座转换器(CCnOutletAdapter
)来,使两个不匹配的接口可以正常工作。插座转换器就是适配器(Adapter
),英式插座是适配者(Adaptee
)。
源码中使用对象适配器方式,这样的好处是,适配器可以有多个适配者,譬如我要兼容美式插座,只需要新增
美式
插座CUsOutlet
,并且将CUsOutlet
作为CCnOutletAdapter
的成员即可。
源码
#include
<iostream>
#include
<string>
using
namespace std;
//
适配器基类
Target,
中式插座
class
CCnOutlet
{
public
:
virtual ~CCnOutlet(){};
virtual void CnPlug(){};
};
//
适配者
Adaptee,
英式插头
class
CEnOutlet
{
public
:
void EnPlug()
{
cout <<"use en plug" <<endl;
}
};
//
适配器
Adapter.
使用对象适配器方式
class
CCnOutletAdapter : public CCnOutlet
{
public
:
CCnOutletAdapter(CEnOutlet*pEnOutlet) :m_pEnOutlet(pEnOutlet) {};
virtual ~CCnOutletAdapter(){};
virtual void CnPlug()
{
cout <<"wanna use cn plug" <<endl;
cout <<"adapter transfer …" <<endl;
m_pEnOutlet->EnPlug();
}
protected
:
CEnOutlet*m_pEnOutlet;
};
int
main()
{
//
适配者当作参数传递给适配器,完成适配过程
CEnOutlet*pEnOutlet =newCEnOutlet;
CCnOutlet*pCnOutlet =newCCnOutletAdapter(pEnOutlet);
pCnOutlet->CnPlug();
delete pEnOutlet;
delete pCnOutlet;
system("pause");
return 0;
}