定义

适配器(Adapter)又叫包装器(Wrapper),是一种类对象结构性模式,目的是将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

分类

适配器有两种实现方式,分别是类适配器和对象适配器。这两种实现方式不太一样。

  • 类适配器:通过多继承的方式来实现
  • 对象适配器:通过对象组合的方式来实现

类适配器


C++设计模式--适配器模式_多继承

对象适配器


C++设计模式--适配器模式_设计模式_02

说明:

  • Target:定义 Client 使用的与特定领域相关的接口
  • Client:与符合 Target 接口的对象协同
  • Adaptee:定义一个已经存在的接口,这个接口需要适配
  • Adapter:对 Adaptee 的接口与 Target 接口进行适配

适用性

以下几种情况可以使用 Adapter 模式

  • 你想使用一个已经存在的类,而它的接口不符合你的要求
  • 你想要创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
  • (仅适用于对象 Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它的接口。对象适配器可以适配它的父类接口。

两种适配器的区别和特点

以上说了两种适配器的原理,那么,在项目中该如何选择哪种类型的适配器呢?接下来详细看看这两种适配器的特点。

类适配器

  • 用一个具体的 Adapter 类对 Adaptee 和 Target 进行匹配。结果是当我们想要匹配一个类以及它的所有子类时,类 Adapter 将不能胜任工作。
  • Adapter 可以重定义 Adaptee 的部分行为,因为Adapter 是 Adaptee 的子类
  • 仅仅引入了一个对象,并不需要额外的指针以间接得到 adaptee 对象

对象适配器

  • 允许一个 Adapter 与多个 Adaptee----即 Adaptee 本身以及它的所有子类同时工作。Adapter 可以一次给所有的 Adaptee 添加功能。
  • 使得重定义 Adaptee 的行为会比较困难。这需要生成Adaptee 的子类并且使得 Adapter 引用这个子类而不是引用 Adaptee 本身。

OK,说了这么多,都是理论的东西,接下来结合示例来理解。

示例

大家都知道,小鸟只能在天上飞,但是不能在水里游,那如果我们想要它能在水里游怎么办呢(我也是异想天开,哈哈哈),那就得给它赋予一点魔法,能够拥有游泳的技能(感觉创造了一个新物种)。OK,来看一下代码:

对象适配器
#include <iostream>

using namespace std;
//target
//创建目标接口
class Bird
{
public:
virtual void swimming() = 0;
};

//adaptee
//创建适配者,就是希望拥有的技能
class SwimmingSkills
{
public:
void CanSwim(){
cout << "I can finally swim." << endl;
}
};

//创建适配器
class SwimAdapter : public Bird
{
public:
SwimAdapter(){
m_pSwimmingSkills = new SwimmingSkills;
}
~SwimAdapter(){
if(m_pSwimmingSkills){
delete m_pSwimmingSkills;
m_pSwimmingSkills = nullptr;
}
}
virtual void swimming(){
m_pSwimmingSkills->CanSwim();
}

private:
SwimmingSkills * m_pSwimmingSkills = nullptr;
};

int main()
{
SwimAdapter adapter;
adapter.swimming();
return 0;
}

可以看到,经过适配,现在小鸟也可以在水里游泳啦,哈哈哈哈。

类适配器

类适配器的方式就直接多继承来实现啦,修改以上示例:

class SwimAdapter1 : public Bird ,SwimmingSkills
{
public:
virtual void swimming(){
CanSwim();
}
};

其他的代码保持不变。这种方式看起来好像代码更简单,但是真正在项目中时,要尽量避免使用多继承的方式,可能会导致混淆(关于这部分,后期再单独介绍)。大家可以根据上述的两种适配器的优缺点来进行选择。