小言_互联网的博客

设计模式回顾——适配器模式(C++)

372人阅读  评论(0)


1 前言

  上一篇文章中对创建型设计模式之一的“建造者模式”进行概述与总结,分别描述了创建者模式含义、组成要素、特点、优缺、适用场景以及实现过程步骤,并以C++语言实现具体例子。本文描述另一设计模式——适配器模式。


2 什么是适配器模式

2.1 生活中的适配器

  平常生活中,我们使用最多的就是“电源适配器”了,电源适配器可以将220V市电转换为我们需要的电压,如手机充电器、笔记本电源等。另外,关于手机数据线问题,经常会遇到苹果Lightning、安卓Micro USB、安卓Type-C接口不兼容问题,也就产生了三者之间的相互转换接头(适配器)。因此,适配器就是将一个接口转换为我们需要的接口,而不是改变目的者的接口。

Micro USB转Type-C适配器

2.2 适配器模式含义

   适配器(Adapter )模式, 就是定义一个第三方封装类,将一个类的接口转换成客户期望的另外一个接口,使得原本由于接口不兼容导致不能一起工作的类可以一起工作。 比如,现在有一根Micro USB接口的数据线,而手机接口是Type-C,两者不能直接使用;通过一个Micro USB转Type-C的适配头即可进行使用。


  适配器模式根据实现过程的不同,分为类模型适配器对象模型适配器

  • 类模型适配器:通过接口继承实现,适配器与适配者之间是继承(实现)关系
  • 对象模型适配器:通实现继承实现,适配器与适配者之间是关联关系;对象模型适配器使用较多

接口继承和实现继承是面向对象领域的两个重要的概念:
  • 接口继承,指的是通过继承,子类获得了父类的接口
  • 实现继承,指的是通过继承,子类获得了父类的实现

2.3 适配器模式作用

  将一个类的接口转换成客户期望的另外一个接口,使得原本由于接口不兼容导致不能一起工作的类可以一起工作。


3 适配器模式优缺点

3.1 适配器优缺点

优点:

  • 解耦

    目标类与适配者解耦,通过引入一个适配器类来复用现有的适配者类,无须修改原有结构代码。

  • 类透明性

    将具体的业务实现过程封装在适配者类中,对于客户端类来说是透明的。

  • 复用性

    系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式可以将其他类封装为系统需要的类,实现功能更好的复用;此外,同一个适配者类可以在多个不同的系统中复用。

  • 灵活性好和易于拓展

    无需更改用户接口和适配者代码,易于拓展,符合“开闭原则“。


不足:

  • 可能导致软件架构凌乱

    过多的使用适配器,会让软件系统非常零乱,不易对软件框架整体进行把控。


3.2 类适配器优缺点

优点:

  • 代码简单,方便实现

    仅仅引入一个对象,并不需要额外的字段来引用Adaptee实例


不足:

  • 高耦合,灵活性低

    类适配器采用对象继承方式实现,相当于静态定义。

  • 单一适配

    对于Java、C#等不支持多重类继承的语言,一次只能适配一个适配者类,不能同时适配多个适配者。


3.3 对象适配器优缺点

优点:

  • 低耦合,灵活性高

    对象适配器采用对象组合方式实现,相当于动态定义。


不足:

  • 使用较为复杂

    引入对象实例,实现上要较为复杂。

  • 更换适配者类复杂

    对象适配器需要更换掉适配者类的一个或多个方法,可以先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。 。


4 什么地方使用适配器模式

4.1 适配器模式适用场景

   适配器模式的优点决定了其适用的场景,反过来其缺点即是其不适用的场景。适配器模式适用场景:

  • 用户需要复用已有类(模块),而该模块的接口与复用环境要求不一致,可以使用适配器模式将该模块适配到用户适合的接口
  • 多个组件功能类似,但接口不统一且可能会经常切换,可使用适配器模式,使得客户可以以统一的接口使用这些组件

具体实例:

  • 使用第三方库,将库接口适配到自己的系统中,算法、支付、加密等
  • 复用公司内部开发的成熟模块
  • 软件架构更新(接口有变动),但需兼容旧的软件模块
  • 将日志模块输出到串口重定向输出到U盘、网口等
  • 网络模块统一以太网、WiFi、蜂窝网、蓝牙等接口

  适配器模式进一步细分,类适配器和对象适配器又适用于不同场景。


4.2 类适配器适用场景

  • 简单实现适配器
  • 需要重新定义Adaptee的部分行为,因为类适配器通过子类覆盖父类方法即可实现

对于对象适配器,如果需要重新定义Adaptee行为,会比较复杂和繁琐,因为需要定义Adaptee的子类来实现。


4.3 对象适配器适用场景

  • 更灵活的适配场景
  • 需同时适配源类和其子类的场景

适配器模式通常使用对象适配器模式,优先考虑合成、聚合方法非继承方法实现,符合”合成复用原则“。


5 适配器模式实现

5.1 类适配器模式

  类模型适配器,即是通过接口继承方式实现,将适配类接口转换为用户期望接口。此时,适配器与适配者之间是继承关系。

5.1.1 UML图

类适配器模式UML模型

5.1.2 类适配器实例

实例情况:

  • 用户期望接口是Request
  • 适配类接口是SpecificRequest
  • 通过类适配器模式将SpecificRequest接口转换为Request接口

实现过程:

  • 第一步,声明用户目标类Target
/* adaptee.h */
#ifndef _ADAPTEE_H_
#define _ADAPTEE_H_

/* 目标接口类,客户期望的接口 */
class Target
{
   
public:
    Target();
    virtual ~Target();
    virtual void Request();	/* 标准接口 */
};
#endif

  • 第二步,声明待适配类Adaptee
/* adaptee.h */
#ifndef _ADAPTEE_H_
#define _ADAPTEE_H_

/* 需要适配的类 */
class Adaptee
{
   
public:
    Adaptee();
    ~Adaptee();
    void SpecificRequest();/* 需适配类接口 */
};
#endif

  • 第三步,目标类和适配类方法
/* adaptee.cpp */
#include "adaptee.h"
#include <iostream>

using namespace std;

Target::Target()
{
   }

Target::~Target()
{
   }

void Target::Request()
{
   
    cout << "Call Target::Request()" << endl;	/* 子类重写该方法,不会调用父类方法 */
}

Adaptee::Adaptee()
{
   
}

Adaptee::~Adaptee()
{
   
}

void Adaptee::SpecificRequest()
{
   
    cout << "Call Adaptee::SpecificRequest()" << endl;
}
  • 第四步,声明适配器类
/* adapter.h */
#ifndef _ADAPTER_H_
#define _ADAPTER_H_

/* 类模型适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果 */
class Adapter:public Target,private Adaptee
{
   
public:
    Adapter();
    ~Adapter();
    virtual void Request();/* 期望接口实现 */
};
#endif

  • 第五步,实现适配器类方法
/* adapter.cpp */
#include "adapter.h"
#include <iostream>

using namespace std;

Adapter::Adapter()
{
   
}

Adapter::~Adapter()
{
   
}

void Adapter::Request()
{
   
    cout << "Call Adapter::Request()" << endl;	/* 重写父类方法,并调用适配类方法 */
    this->SpecificRequest();
}

  • 第六步,用户调用
/* client.cpp */
#include "adapter.h"

int main(int arc, char **argv)
{
   
    Target* target = new Adapter();
    target->Request();
	delete target;
    return 0;
}

执行结果:

acuity@ubuntu:/mnt/hgfs/LSW/STHB/design-mode/adapter$ g++ -o client client.cpp adapter.cpp adaptee.cpp 
acuity@ubuntu:/mnt/hgfs/LSW/STHB/design-mode/adapter$ ./client
Call Adapter::Request()
Call Adaptee::SpecificRequest()

5.2 对象适配器模式

  对象模型适配器,即是通实现继承实现,将适配类接口转换为用户期望接口。此时,适配器与适配者之间是关联(组合)关系。

5.2.1 UML图

对象适配器模式UML模型

5.2.2 对象适配器实例

实例情况:

  • 用户期望接口是Request
  • 适配类接口是SpecificRequest
  • 通过类适配器模式将SpecificRequest接口转换为Request接口

实现过程:

  • 第一步,声明用户目标类Target
/* adaptee.h */
#ifndef _ADAPTEE_H_
#define _ADAPTEE_H_

/* 目标接口类,客户期望的接口 */
class Target
{
   
public:
    Target();
    virtual ~Target();
    virtual void Request();	/* 标准接口 */
};
#endif

  • 第二步,声明待适配类Adaptee
/* adaptee.h */
#ifndef _ADAPTEE_H_
#define _ADAPTEE_H_

/* 需要适配的类 */
class Adaptee
{
   
public:
    Adaptee();
    ~Adaptee();
    void SpecificRequest();/* 需适配类接口 */
};
#endif

  • 第三步,目标类和适配类方法
/* adaptee.cpp */
#include "adaptee.h"
#include <iostream>

using namespace std;

Target::Target()
{
   }

Target::~Target()
{
   }

void Target::Request()
{
   
    cout << "Call Target::Request()" << endl;	/* 子类重写该方法,不会调用父类方法 */
}

Adaptee::Adaptee()
{
   
}

Adaptee::~Adaptee()
{
   
}

void Adaptee::SpecificRequest()
{
   
    cout << "Call Adaptee::SpecificRequest()" << endl;
}
  • 第四步,声明适配器类
/* adapter.h */
#ifndef _ADAPTER_H_
#define _ADAPTER_H_

#include "adaptee.h"

/* 对象模型适配器类,通过public继承获得接口继承的效果,采用组合的方式实现Adaptee的复用 */
class Adapter:public Target
{
   
public:
    Adapter(Adaptee *adaptee);	/* 构造函数1 */
    Adapter();	/* 构造函数2 */
    ~Adapter();
    virtual void Request();/* 期望接口实现 */
private:
    Adaptee *adaptee;
};
#endif

  • 第五步,实现适配器类方法
/* adapter.cpp */
#include "adapter.h"
#include <iostream>

using namespace std;

Adapter::Adapter(Adaptee *adaptee)
{
   
	this->adaptee = adaptee;
}

Adapter::Adapter():adaptee(new Adaptee)
{
   
	this->adaptee = adaptee;
}

Adapter::~Adapter()
{
   
}

void Adapter::Request()
{
   
    cout << "Call Adapter::Request()" << endl;	/* 重写父类方法,并通适配类对象调用适配类方法 */
    this->adaptee->SpecificRequest();
}

  • 第六步,用户调用
/* client.cpp */
#include "adapter.h"

int main(int arc, char **argv)
{
   
    /* 构造函数1创建对象 */
    Adaptee* adaptee = new Adaptee();
    Target* target0= new Adapter(adaptee);
    target0->Request();
	delete adaptee;
	delete target0;
	
    /* 构造函数2创建对象 */
    Target* target1 = new Adapter();
    target1->Request();
	delete target1;
	
    return 0;
}

执行结果:

acuity@ubuntu:/mnt/hgfs/LSW/STHB/design-mode/adapter1$ g++ -o client client.cpp adapter.cpp adaptee.cpp 
^[[Aacuity@ubuntu:/mnt/hgfs/LSW/STHB/design-mode/adapter1$ ./client
Call Adapter::Request()
Call Adaptee::SpecificRequest()
Call Adapter::Request()
Call Adaptee::SpecificRequest()

转载:https://blog.csdn.net/qq_20553613/article/details/109036187
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场