一、概述
Adapter(适配器)模式又称Wrapper模式,主要用于将一个类的接口转换成客户希望的另外一个接口,解决两个已有接口之间不匹配的问题。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。因此,Adapter模式经常被描述成第三方函数库或旧的程序库与现有系统接口
/需求不一致时的救星,也正是由于Adapter模式的这种特性,有人也将Adapter模式比喻成变压器,变压器把一种电压变换成另一种电压。美国的生活用电电压是110V,而中国的电压是220V。如果要在中国使用美国电器,就必须有一个能把220V电压转换成110V电压的变压器,这个变压器就是一个Adapter。
二、结构
在GoF的DP一书中给出了两种Adapter模式的应用:Class Adapter和Object Adapter,两种应用模式的类图如下所示:
图
1:Class Adapter
其中涉及的角色包括:
目标(Target)角色:这是客户所期待的接口。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:把源接口转换成目标接口。这一角色必须是类。
图
2:Object Adapter
其中涉及的角色包括:
目标(Target)角色:这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:通过在内部包装(Wrap)一个Adaptee对象,把源接口转换成目标接口。
Class Adapter中adapter类通过继承adaptee类获得adaptee类的功能,
而Object Adapter中adpter通过包容(composite)adaptee获得其功能。
基于“当涉及到依存性时,应当始终优先选择组合
/成员关系而不是继承”的设计原则(
<Exceptional C
++>),并且由于多继承在使用上的复杂性,及在部分情况下不可行等原因,Object Adapter的运用显得更加广泛。
此外,当需要改变多个已有子类的接口时,如果使用Class Adapter模式,就要针对每一个子类做一个适配器,而这不太实际,此时比较适合使用Object Adapter。
Object Adapter模式的基本思想在于:Delegate委托,即将需要完成的工作交给adaptee去完成,当然,为了兼容Client需求与adaptee接口之间的不一致,在委派的过程中,我们往往也需要作一些适当的调整。
三、应用
Adapter模式可应用于如下的情况:
1、系统需要使用现有的类,而此类的接口不符合系统的需要。(示例
1、
2、
3均属于这种情况,只是出发点稍有不同)
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有与一致的接口。这种情况从不同的角度考虑,可能被划入Facade模式的范畴,但从与现有设计适配的角度考虑该问题,则将其划归Adapter模式也是可以理解的。
3、通过接口转换,将一个类插入另一个类系中。有人举过这样一个例子:虎与飞禽是没有直接关联的两类动物,但是现在出来了个“飞虎”,它同时具有虎肉食动物跟飞禽会飞的特质,要在飞禽这个类系中添加一个成员类“飞虎”,除了直接实现“飞虎”类,还有一种简单的办法是实现一个Adapter类,在其中包容一个虎的对象,同时实现飞禽的接口即可。当然,对于这个问题,多继承或者实现多接口可能是一个更直观的作法,在实际应用中,可视具体需要确定采用何种作法。
四、优缺点
五、举例
在使用C++实现类适配器时,Adapter类应该采用公共方式继承Target类,并且用私有方式继承Adaptee类。因此,Adapter类应该是Target的子类型,但不是Adaptee的子类型.
在使用C++实现对象适配器时,Adapter类应该采用公共方式继承Target类;同时, 设置Adaptee类作为Adapter类的私有成员.
// class Adaptee
class Adaptee
{
public:
void SpecialRequest(){cout<<"This is a design model!"<<endl;}
} ;
// class Target
class Target
{
public:
virtual void Request() = 0 ;
} ;
// class Adapter
class Adapter : public Target, private Adaptee
{
public:
virtual void Request() { SpecialRequest() ; }
} ;
//客户端代码:
void main()
{
Target *p = new Adapter() ;
p->Request() ; //实际上调用的是SpecialRequest()
}
下面是对象Adapter的实现代码:
// class Adaptee
class Adaptee
{
public:
void SpecialRequest(){cout<<"This is a design model!"<<endl;}
} ;
// class Target
class Target
{
public:
virtual void Request() = 0 ;
} ;
// class Adapter
class Adapter : public Target
{
public:
virtual void Request() { _adaptee.SpecialRequest() ; }
private:
Adaptee _adaptee;
//对象Adapter的实现,将其定义为一个Adapter的私有成员,然后通过上面的Request函数实现调用
};
//客户端代码:
void main()
{
Target *p = new Adapter() ;
p->Request() ; //实际上调用的是SpecialRequest()
}
六、相关模式
Bridge:
Bridge模式的结构与对象适配器类似,但是Bridge模式的出发点不同: Bridge目的是将接口部分和实现部分分离,从而对它们可以较为容易也相对独立的加以改变。而Adapter则意味着改变一个已有对象的接口.
Decorator:
Decorator模式增强了其他对象的功能而同时又不改变它的接口。因此Decorator对应用程序的透明性比适配器要好。结果是Decorator支持递归组合,而纯粹使用适配器是不可能实现这一点的.
Proxy:
Proxy模式在不改变它的接口的条件下,为另一个对象定义了一个代理.