设计模式:适配器模式(Adapter)

设计模式:适配器模式(Adapter)

  • 设计模式:适配器模式(Adapter)
    • 模式动机
    • 模式定义
    • 模式结构
    • 时序图
    • 模式实现
    • 在单线程环境下的测试
    • 在多线程环境下的测试
    • 模式分析
    • 优缺点
    • 适用场景
    • 应用场景
    • 应用实例
    • 适配器模式和代理模式的区别
    • 模式扩展
      • 默认适配器模式(Default Adapter Pattern)
      • 接口适配器模式
    • 参考

设计模式:适配器模式(Adapter)

适配器模式(Adapter)属于结构型模式(Structural Pattern)的一种。

结构型模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。

结构型模式可以分为类结构型模式和对象结构型模式:

  • 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
  • 对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。

模式动机

通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。

在这种情况下,现有的接口需要转化为客户类期望的接口,这样保证了对现有类的重用。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。

模式定义

适配器模式(Adapter)别名为包装器(Wrapper)模式,属于结构型模式。它既可以作为类结构型模式,也可以作为对象结构型模式。

适配器模式(Adapter)将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

模式结构

适配器模式(Adapter)包含如下角色:

  • 抽象目标(Target):一个抽象类,定义需要适配的标准接口。
  • 适配器类(Adapter):充当中间转换角色,该对象将源对象转换成目标接口。
  • 适配者类(Adaptee) / 源对象(Source):需要被适配的不兼容对象。
  • 客户(Client):通过目标类(Target)的接口访问它所提供的服务。

适配器模式有对象适配器和类适配器两种实现。

对象适配器:

在这里插入图片描述

类适配器:

在这里插入图片描述

时序图

在这里插入图片描述

模式实现

抽象目标 Target.h:

#ifndef _TARGET_H_
#define _TARGET_H_class Target
{
public:virtual void request() = 0;
};#endif // !_TARGET_H_

适配者类 Adaptee.h:

#ifndef _ADAPTEE_H_
#define _ADAPTEE_H_#include <iostream>class Adaptee
{
public:void specificRequest(){std::cout << "Adaptee::specificRequest" << std::endl;}
};#endif // !_ADAPTEE_H_

对象适配器 ObjectAdapter.h:

#ifndef _OBJECT_ADAPTER_H_
#define _OBJECT_ADAPTER_H_#include "Target.h"
#include "Adaptee.h"class ObjectAdapter : public Target
{
private:Adaptee* m_pAdaptee;public:ObjectAdapter(Adaptee* pAdaptee) :m_pAdaptee(pAdaptee) {};virtual ~ObjectAdapter(){delete m_pAdaptee;}virtual void request(){std::cout << "ObjectAdapter::request" << std::endl;m_pAdaptee->specificRequest();}
};#endif // !_OBJECT_ADAPTER_H_

类适配器 ClassAdapter.h:

#ifndef _CLASS_ADAPTER_H_
#define _CLASS_ADAPTER_H_#include "Target.h"
#include "Adaptee.h"class ClassAdapter : public Target, public Adaptee
{
public:virtual void request(){std::cout << "ClassAdapter::request" << std::endl;this->specificRequest();}
};#endif // !_CLASS_ADAPTER_H_

在单线程环境下的测试

测试代码,也可以说是 client:

#include <stdlib.h>#include "ClassAdapter.h"
#include "ObjectAdapter.h"
#include "Adaptee.h"
#include "Target.h"using namespace std;int main(int argc, char* argv[])
{Adaptee* adaptee = new Adaptee();Target* tar1 = new ClassAdapter();Target* tar2 = new ObjectAdapter(adaptee);tar1->request();tar2->request();delete adaptee;delete tar1;delete tar2;system("pause");return 0;
}

运行结果:

在这里插入图片描述

在多线程环境下的测试

略。

模式分析

  • 对象适配器模式:继承抽象目标类(Target),实现目标接口的所有方法,使用复合的方式,拥有一个适配者类(Adaptee)的对象,调用需要适配对象的方法。
  • 类适配器模式:同时继承抽象目标类(Target)和适配者类(Adaptee),实现目标接口的所有方法,同时继承适配者类的实现,用以完成一些适配逻辑。

优缺点

优点:

  1. 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
  2. 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
  3. 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

类适配器模式还具有如下优点:由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。

对象适配器模式还具有如下优点:一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

缺点:

  1. 过多的适配器会导致系统结构复杂。
  2. 如果适配器没有实现好,可能会拖慢整个系统的性能。
  3. 滥用适配器模式会导致系统设计紊乱。

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

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

适用场景

在以下情况下可以使用适配器模式:

  1. 系统需要使用现有的类,而这些类的接口不符合系统的需要。
  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

应用场景

  1. 电压转换器:不同国家的电压规格各异,同样功率的电器在不同的地方工作时需要不同的电压,电压转换器作为适配器,将不同电压转换成电器使用标准电压。
  2. 耳机转接头:有些手机没有耳机插口,需要使用转接头适配器,将耳机转换为手机支持的接口,实现对不同的耳机兼容。
  3. JDBC驱动程序:不同的数据库提供商(如SQL Server、Oracle、MySQL等)实现了不同的JDBC驱动接口,使用适配器模式可以将这些不同的接口适配为标准的JDBC接口,提高应用程序的可移植性。
  4. 日志框架:Java中有多个常用的日志框架,如Log4j、SLF4J等,不同的日志框架提供的API不同,使用适配器模式可以将这些不同的API适配为一个统一的接口,方便再程序中进行日志记录和管理。
  5. 第三方库或SDK:在使用第三方库或 SDK 时,可能由于它们实现的 API 不同而导致应用程序复杂,使用适配器模式可以将不同的 API 适配为统一的接口,简化应用程序的调用。

应用实例

当我们去国外旅游时,我们可能只会汉语,而当地人只会英语,那么这个时候就需要一个翻译员(翻译软件)来帮助我们。这就类似于适配器模式,通过一个适配器将一个不兼容的接口转成另外一个接口。下面以翻译为例,介绍一下类、接口、对象适配器。

  • 目标接口 Target:里面定义了一个 translate 方法。
  • 翻译类 Translator:就是适配者类,里面有 TranslateInZh 和 TranslateInEn 方法。
  • 对象适配器 ObjectAdapter 和类适配器 ClassAdapter。

对象适配器模式:

在这里插入图片描述

类适配器模式:

在这里插入图片描述

完整程序:

#include <iostream>
#include <stdlib.h>
using namespace std;class Target
{
public:virtual void translate(string source, string target, string words) = 0;
};class Translator
{
public:void translateInZh(string words){if (words == "hello world!")cout << "你好世界!" << endl;}void translateInEn(string words){if (words == "你好世界!")cout << "Translate in English: \"hello world!\"" << endl;}
};class ClassAdapter : public Target, public Translator
{
public:virtual void translate(string source, string target, string words){if (source == "中文" && target == "英文")this->translateInEn(words);elsethis->translateInZh(words);}
};class ObjectAdapter : public Target
{
private:Translator *m_pTranslator;public:ObjectAdapter(Translator *trans) : m_pTranslator(trans){};virtual ~ObjectAdapter(){delete m_pTranslator;}virtual void translate(string source, string target, string words){if (source == "中文" && target == "英文")m_pTranslator->translateInEn(words);elsem_pTranslator->translateInZh(words);}
};int main()
{Translator* translator = new Translator();Target *tar1 = new ClassAdapter();Target *tar2 = new ObjectAdapter(translator);tar1->translate("中文", "英文", "你好世界!");tar1->translate("英文", "中文", "hello world!");cout << endl;tar2->translate("中文", "英文", "你好世界!");tar2->translate("英文", "中文", "hello world!");system("pause");return 0;
}

运行结果:

在这里插入图片描述

适配器模式和代理模式的区别

适配器模式的主要目的是使接口不兼容的对象能够协同工作。适配器模式允许将⼀个类的接口转换成另⼀个类的接口,使得不同接⼝的类可以协同工作。

代理模式的主要目的是控制对对象的访问。通常⽤于在访问真实对象时引入⼀些额外的控制逻辑,如权限控制、延迟加载等。

模式扩展

默认适配器模式(Default Adapter Pattern)

也称为缺省适配器模式。

当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。因此也称为单接口适配器模式。

接口适配器模式

主要适用于需要被适配的接口中,只有用到个别接口,也就是说不需要实现它的全部接口。通过一个中间抽象类或接口实现。

在这里插入图片描述

参考

  1. https://design-patterns.readthedocs.io/zh-cn/latest/structural_patterns/adapter.html#
  2. https://www.runoob.com/design-pattern/adapter-pattern.html
  3. https://blog.csdn.net/weixin_45433817/article/details/131037102

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/332692.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新书推荐:7.1 do while语句

本节必须掌握的知识点&#xff1a; 示例二十二 代码分析 汇编解析 ■do while语句其语法形式&#xff1a; do{ 语句块; }while(表达式) ■语法解析&#xff1a; ●执行do循环体内的语句块&#xff1b; ●判断while语句里的表达式&#xff0c;表达式为真继续下次循环&#…

上位机图像处理和嵌入式模块部署(f103 mcu运行freertos)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 mcu一般有两个用途,一个是控制,一个是非控制。控制类的应用一般要求实时性比较高,什么时候做什么,都是有严格的时间要求的。而非控制类的应用,则要求实现尽可能多的功能,比如…

PanTools v1.0.25 多网盘批量管理工具 批量管理、分享、转存、重命名、复制...

一款针对多个热门网盘的文件管理、批量分享、批量转存、批量复制、批量重命名、批量链接检测、跨账号移动文件、多账号文件搜索等&#xff0c;支持不同网盘的不同账号的资源文件操作。适用于网站站长、资源爱好者等&#xff0c;对于管理名下具有多个网盘多个账号具有实用的效果…

2024.05.26 第 399 场周赛

Leetcode 第 399 场周赛 优质数对的总数 I Leetcode 优质数对的总数 I 给你两个整数数组 nums1 和 nums2&#xff0c;长度分别为 n 和 m。同时给你一个正整数 k。 如果 nums1[i] 可以被 nums2[j] * k 整除&#xff0c;则称数对 (i, j) 为 优质数对&#xff08;0 < i < n…

React自定义Componment和State深层次理解-07

本节主要从底层原理上分析下React开发相关的内容和注意事项&#xff0c;本节会围绕使用展开&#xff0c;而非源码讲解。 Componment详解 什么是组件 在 MVVM架构出现之前&#xff0c;组件主要分为两种。 狭义上的组件&#xff0c;又称为 UI 组件&#xff0c;比如 Tabs 组件、…

PC端应用订阅SDK接入攻略

本文档介绍了联想应用联运sdk接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运sdk。 1. 接入前准备 1. 请先与联想商务达成合作意向。 2. 联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#xff08;公私钥、…

Linux定时计划

定时计划 一、计划任务种类 突发性&#xff1a;临时决定只执行一次的任务 at&#xff1a;处理执行一次任务就结束定时性&#xff1a;每隔一定时间需要重复执行此命令 crontab&#xff1a;指定任务&#xff0c;按照设定的周期一直循环执行二、作用 定时任务可以用于自动备份…

如何将Windows PC变成Wi-Fi热点?这里提供详细步骤

序言 Windows 10和Windows 11都有内置功能,可以将你的笔记本电脑(或台式机)变成无线热点,允许其他设备连接到它并共享你的互联网连接。以下是操作指南。 由于Windows中隐藏的虚拟Wi-Fi适配器功能,你甚至可以在连接到另一个Wi-Fi网络或无线路由器时创建Wi-Fi热点,通过另…

Navicat 连接 OceanBase 快速入门 | 社区版

Navicat Premium&#xff08;16.1.9或更高版本&#xff09;正式支持 OceanBase全线数据库产品。OceanBase为现代数据架构打造的开源分布式数据库。兼容 MySQL 的单机分布式一体化国产开源数据库&#xff0c;具有原生分布式架构&#xff0c;支持金融级高可用、透明水平扩展、分布…

分布式音乐播放器适配了Stage模型

OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;应用开发自API 8及其更早版本一直使用的是FA模型进行开发。FA模型是Feature Ability的缩写&#xff0c;它和PA&#xff08;Particle Ability&#xff09;两种类型是过往长期推广的术语&#xff0c;深入人心…

95.网络游戏逆向分析与漏洞攻防-ui界面的设计-ui的设计与架构

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

精品丨快速申请免费https证书

https域名证书对提高网站排名有一定的好处&#xff0c;所以当今很多企业为了给网站一个好的安全防护&#xff0c;就会去申请该证书。如今很多企业虽然重视网站的安全防护&#xff0c;但是也重视成本&#xff0c;所以为了节约成本会考虑申请免费的https证书。 第一个好处 企业不…

用Prometheus全面监控MySQL服务:一篇文章搞定

简介 在现代应用中&#xff0c;MySQL数据库的性能和稳定性对业务至关重要。有效的监控可以帮助预防问题并优化性能。Prometheus作为一款强大的开源监控系统&#xff0c;结合Grafana的可视化能力&#xff0c;可以提供全面的MySQL监控方案。 设置Prometheus 安装Prometheus 使…

机器学习预测-CNN手写字识别

介绍 这段代码是使用PyTorch实现的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于在MNIST数据集上进行图像分类。让我一步步解释&#xff1a; 导入库&#xff1a;代码导入了必要的库&#xff0c;包括PyTorch&#xff08;torch&#xff09;、神经网络模块&#xff0…

queue学习

std::queue 类是一种容器适配器&#xff0c;它提供队列的功能——尤其是 FIFO&#xff08;先进先出&#xff09;数据结构。此类模板用处为底层容器的包装器——只提供特定的函数集合。queue 在底层容器尾端推入元素&#xff0c;从首端弹出元素。 元素访问 front 访问第一个元素…

Shell环境变量深入:自定义系统环境变量

Shell环境变量深入&#xff1a;自定义系统环境变量 目标 能够自定义系统级环境变量 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序使用 以后只要是所有Shell程序或命令使用的变量…

0基础认识C语言

为了给0基础一个舒服的学习路径&#xff0c;就有了这个专栏希望带大家一起进步。 话不多说&#xff0c;开始正题。 一、C语言的一段小历史 C语言的设计要追溯到20世纪60年代末和70年代初&#xff0c;在那个时代美国有这么一号人叫做丹尼斯.里奇&#xff0c;他和同事肯.汤普逊…

【vue】el-select选择器实现宽度自适应

选择器的宽度根据内容长度进行变化 <div class"Space_content"><el-selectv-model"value":placeholder"$t(bot.roommessage)"class"select"size"small"style"margin-right: 10px"change"selectcha…

【MySQL】库的基础操作

&#x1f30e;库的操作 文章目录&#xff1a; 库的操作 创建删除数据库 数据库编码集和校验集 数据库的增删查改       数据库查找       数据库修改 备份和恢复 查看数据库连接情况 总结 前言&#xff1a;   数据库操作是软件开发中不可或缺的一部分&#xff0…

若依框架对于后端返回异常后怎么处理?

1、后端返回自定义异常serviceException 2、触发该异常后返回json数据 因为若依对请求和响应都封装了&#xff0c;所以根据返回值response获取不到Code值但若依提供了一个catch方法用来捕获返回异常的数据 3、处理的方法