适配器模式

背景

目标类给客户端提供服务,很多时候都是以API的形式,目标类能偶提供满足要求的服务,但是接口不一定是客户端期望的,方法名,参数列表等不符合客户的要求,本着以客户为中心的理念,不能让客户去更改调用的方式,只能是目标类修改。但如果多个客户所要求的接口不一样,那么目标类到底是要改成什么样呢?适配器模式就是把目标类的接口转化成客户需要的接口,达到适配的目的

现实生活中适配的例子也很多,例如电脑电源适配器,中国生产的电脑的电源是三口插口,可是到了国外,像日本,他们的供电的插槽是两孔的,导致了当时去日本时电脑都没有能充电,因此这时需要一个适配器,将三孔的插口装换成两孔的。

代码示例

//目标类,提供了specificRequest()接口

1
2
3
4
5
6
7
8
9
10
class Adaptee
{
public:
Adaptee();
virtual ~Adaptee();
void specificRequest();
};

//适配器类,提供request(),完成的是目标类specificRequest()的功能,由代码可知,适配器类持有一个目标类的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Adapter.h"
Adapter::Adapter(Adaptee * adaptee){
m_pAdaptee = adaptee;
}
Adapter::~Adapter(){
}
void Adapter::request(){
m_pAdaptee->specificRequest();
}

适配器类和目标类需要实现用一个接口

对象适配器和类适配器

以上的适配器是对象适配器,它和目标类是关联的关系,即持有它的一个对象

类适配器,不是关联的关系,而是继承的关系,如:

1
2
3
4
5
class Adapter extends Adaptee implements Target{
public void request() {
super.specificRequest();
}
}

类适配器采用继承,相对静态;而对象适配器采用关联的方式,持有目标类的引用,利用多态的特性,它可以持有满足同一接口的任意一个对象,因此可以适配一系列的对象,相对灵活。

优点

  1. 将目标类和客户端进行解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。

  2. 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。

  3. 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

缺点

类适配器模式的缺点

对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。

对象适配器模式的缺点

与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。

适用环境

  1. 系统需要使用现有的类,而这些类的接口不符合系统的需要。

  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。