重温设计模式--适配器模式

文章目录

  • 适配器模式(Adapter Pattern)概述
  • 适配器模式UML图
  • 适配器模式的结构
    • 目标接口(Target):
    • 适配器(Adapter):
    • 被适配者(Adaptee):
  • 作用:
  • C++ 代码示例
  • C++示例代码2
  • 应用场景
    • 系统集成与接口兼容
    • 第三方库集成:
    • 旧代码适配新架构:
    • 软件模块交互与协作
    • 跨平台开发中的适配:

适配器模式(Adapter Pattern)概述

定义:
适配器模式是一种结构型设计模式,它的主要作用是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。就好像一个 “转换器”,把不匹配的接口进行适配,让它们能够相互对接使用。

适配器模式UML图

在这里插入图片描述

适配器模式的结构

目标接口(Target):

这是客户端所期望使用的接口,定义了客户端需要调用的方法集合。它代表了一种规范或者协议,客户端代码是基于这个接口来进行操作的。

适配器(Adapter):

它实现了目标接口,同时在内部持有一个被适配者的实例,并通过调用被适配者的相关方法来实现目标接口中定义的方法,以此来完成接口的转换工作,使得客户端可以通过目标接口来间接使用被适配者的功能。

被适配者(Adaptee):

它是已经存在的、具有特定功能但接口不符合要求的类或对象。其接口可能包含与目标接口相似但不完全相同的方法,或者方法名称、参数等方面存在差异。

作用:

解决接口不兼容问题:在软件开发过程中,经常会遇到需要使用一些现有的类,但这些类的接口与当前系统所期望的接口不一致的情况。适配器模式通过创建一个中间适配器类,对原有类的接口进行包装转换,使其符合新的使用要求,从而避免了对原有类进行大规模修改,保护了已有的代码资产。
提高代码的复用性:可以复用那些已经经过测试、功能完善但接口不符合要求的类,只需要添加适配器类来适配接口,就能让它们融入新的系统环境中继续发挥作用,减少了重复开发的工作量。
增强系统的灵活性和可扩展性:当系统需要接入新的外部组件或者更换底层实现时,如果存在接口不兼容的情况,通过编写适配器就能方便地实现对接,使得系统可以更容易地与不同的外部模块集成,应对各种变化。

C++ 代码示例

以下以一个简单的电源适配器的例子来展示适配器模式在代码中的应用。假设我们有一个手机充电器,它期望的输入电压是 5V,而我们现有的电源输出电压是 220V,需要一个适配器来将 220V 的电压转换为 5V 供手机充电器使用。

// 目标接口,代表手机充电器期望的输入接口
class ChargerTarget
 {
public:
    virtual void chargeWith5V() = 0;
};

// 被适配者,代表现有的220V电源,有输出220V电压的方法
class PowerSource 
{
public:
    void output220V() 
    {
        std::cout << "输出220V电压" << std::endl;
    }
};

// 适配器类,将220V电源适配成手机充电器能用的5V电源
class VoltageAdapter : public ChargerTarget
 {
private:
    PowerSource* powerSource;
public:
    VoltageAdapter(PowerSource* source)
     {
        powerSource = source;
    }
    void chargeWith5V() override
     {
        powerSource->output220V();
        std::cout << "经过适配器转换,输出5V电压用于充电" << std::endl;
    }
};

int main() 
{
    PowerSource powerSource;
    VoltageAdapter adapter(&powerSource);
    ChargerTarget* charger = &adapter;
    charger->chargeWith5V();
    return 0;
}

在上述代码中:
ChargerTarget是目标接口,定义了chargeWith5V方法,代表手机充电器期望的输入接口规范,客户端希望调用这个接口来实现充电功能。
PowerSource是被适配者,它原本有自己的output220V方法,输出的是 220V 电压,不符合手机充电器直接使用的要求。
VoltageAdapter是适配器类,它实现了ChargerTarget接口,内部持有PowerSource对象的指针。在chargeWith5V方法中,先调用PowerSource的output220V方法获取 220V 电压,然后模拟进行转换,输出符合要求的 5V 电压,从而使得原本不匹配的电源和手机充电器能够协同工作,体现了适配器模式的基本原理和应用方式。
除了这种类适配器的形式(通过继承来实现适配),还有对象适配器(通过组合的方式,将被适配者对象作为适配器类的成员变量,代码结构稍有不同,但核心思想一致),可根据具体的应用场景和设计需求来选择合适的实现方式。

C++示例代码2

#include<iostream>
#include<string>
using namespace std;
//抽象球员类
class player
{
	protected:
	string m_name;
public:
	player(string str_name):m_name(str_name){}
	virtual void attack(){};
	virtual void defends(){};
};
//具体球员 前锋
class forwords:public player
{
public:
	forwords(string str_name):player(str_name){}
	void attack()
	{
		cout<<m_name<<"进攻"<<endl;
	}
	void defends()
	{
		cout<<m_name<<"防守"<<endl;
	}
};
//中锋
class center:public player
{
public:
	center(string str_name):player(str_name){}
	void attack()
	{
		cout<<m_name<<"进攻"<<endl;
	}
	void defends()
	{
		cout<<m_name<<"防守"<<endl;
	}
};

class yaoming
{
private:
	string m_name;
public:
	yaoming(string str_name):m_name(str_name){}
	void attack_yaoming()
	{
		cout<<m_name<<"进攻"<<endl;
	}
	void defends_yaoming()
	{
		cout<<m_name<<"防守"<<endl;
	}
};

class translate:public player
{
private:
	yaoming *s;
public:
	translate(string str_name):player(str_name)
	{
		s = new yaoming("姚明");
	}

	void attack()
	{
		s->attack_yaoming();
	}
	void defends()
	{
		s->defends_yaoming();
	}
	
};


int main()
{
	player *s = new forwords("A");
	s->attack();

	player *s1 = new forwords("B");
	s1->attack();

	player *m_yaoming = new translate("姚明");
	m_yaoming->defends();
	m_yaoming->attack();
	return 0;
}

应用场景

系统集成与接口兼容

不同数据库的适配:当应用程序需要从一个数据库系统(如 MySQL)切换到另一个数据库系统(如 Oracle)时,由于数据库的 API 接口不同,就可以使用适配器模式。例如,原来的代码是基于 MySQL 的SELECT语句来查询数据,接口可能是mysql_query()函数。当切换到 Oracle 时,其查询接口是OCIStmtExecute()函数。可以创建一个适配器类,实现原来基于 MySQL 接口风格的函数,在内部将其转换为 Oracle 对应的函数调用,这样就可以在不大量修改上层业务逻辑代码的情况下完成数据库的替换。

第三方库集成:

在软件开发中,常常会使用第三方库来实现一些功能。如果第三方库的接口与项目中其他部分的接口不兼容,就可以使用适配器模式来整合。比如,一个图形绘制库的接口是接收坐标点的数组来绘制多边形,而项目中现有的图形数据存储格式是一系列的线段对象。这时可以创建一个适配器,将线段对象转换为坐标点数组的格式,使其能够被图形绘制库所使用。
旧系统改造与复用

旧代码适配新架构:

在对旧系统进行升级改造时,可能会引入新的架构或者设计模式。如果旧系统中的一些功能模块的接口不符合新架构的要求,就可以通过适配器模式来进行适配。例如,旧系统中有一个用户认证模块,它的接口是直接返回用户的基本信息字符串,而新架构要求通过一个对象来传递用户信息,包括用户名、密码、权限等多个属性。可以创建一个适配器类,将旧接口返回的字符串解析并封装成新架构所需要的用户信息对象,从而使旧的用户认证模块能够在新架构中继续使用。
硬件设备接口适配:在工业控制或者智能家居系统中,可能会存在新的控制系统与旧的硬件设备接口不匹配的情况。例如,新的智能控制系统期望通过网络协议接收和发送设备状态信息,而旧的传感器设备只有简单的串口通信接口并且数据格式不同。通过适配器模式,可以创建一个设备接口适配器,将串口通信的数据格式转换为网络协议的数据格式,并且处理通信方式的差异,使得旧设备能够在新的智能控制系统中正常工作。

软件模块交互与协作

不同模块间接口转换:在一个大型软件系统中,不同的模块可能是由不同的团队开发的,它们的接口设计可能没有考虑到相互之间的协作。当需要将这些模块集成在一起时,就可能会出现接口不兼容的问题。例如,一个数据处理模块输出的数据结构是链表形式,而另一个数据分析模块期望的数据结构是数组形式。可以通过适配器模式,创建一个数据结构适配器,将链表数据转换为数组数据,使得两个模块能够顺利地进行数据交互。

跨平台开发中的适配:

在跨平台应用开发中,不同的操作系统(如 Windows、Linux、macOS)提供的 API 接口有所不同。例如,在 Windows 系统中,创建窗口的函数是CreateWindow(),而在 Linux 系统下可能是通过XCreateWindow()函数(基于 X Window 系统)。为了使应用程序能够在不同的操作系统上运行,可以使用适配器模式。创建一个窗口创建适配器类,在不同的操作系统下实现不同的窗口创建函数,但是对外提供统一的窗口创建接口,这样就可以在跨平台开发中方便地处理操作系统接口的差异。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flamingo:少样本多模态大模型

Flamingo&#xff1a;少样本多模态大模型 论文大纲理解1. 确认目标2. 分析过程&#xff08;目标-手段分析&#xff09;3. 实现步骤4. 效果展示5. 金手指 解法拆解全流程核心模式提问Flamingo为什么选择使用"固定数量的64个视觉tokens"这个特定数字?这个数字的选择背…

[spring]处理器

我们可以通过spring来管理我们的类&#xff0c;之后我们可以通过spring的容器来获取我们所需要的Bean类对象。Spring的处理器是Spring对外开发的重要扩展点&#xff0c;它允许我们介入到Bean的整个实例化流程中来&#xff0c;可以动态添加、修改BeanDefinition、动态修改Bean 首…

git企业开发的相关理论(二)

目录 git企业开发的相关理论&#xff08;一&#xff09; 八.修改文件 九.版本回退 十.撤销修改 情况一(还没有add) 情况二(add后还没有commit) 情况三(commit后还没有push) 十一.删除本地仓库中的文件 方法一 方法二 十二.理解分支 1.常见的分支工作流程 2.合并冲…

计算机网络压缩版

计算机网络到现在零零散散也算过了三遍&#xff0c;一些协议大概了解&#xff0c;但总是模模糊糊的印象&#xff0c;现在把自己的整体认识总结一下&#xff0c;&#xff08;本来想去起名叫《看这一篇就够了》&#xff0c;但是发现网上好的文章太多了&#xff0c;还是看这篇吧&a…

重温设计模式--状态模式

文章目录 状态模式&#xff08;State Pattern&#xff09;概述状态模式UML图作用&#xff1a;状态模式的结构环境&#xff08;Context&#xff09;类&#xff1a;抽象状态&#xff08;State&#xff09;类&#xff1a;具体状态&#xff08;Concrete State&#xff09;类&#x…

JVM执行引擎JIT深度剖析

前端编译与后端编译 Java 程序的编译过程是分两个部分的。一个部分是从java文件编译成为class文件&#xff0c;这一部分也称为前端编译。另一个部分则是这些class文件&#xff0c;需要进入到 JVM 虚拟机&#xff0c;将这些字节码指令编译成操作系统识别的具体机器指令。这一部…

五分钟学会如何在GitHub上自动化部署个人博客(hugo框架 + stack主题)

上一篇文章&#xff1a; 10分钟学会免费搭建个人博客&#xff08;Hugo框架 stack主题&#xff09; 前言 首先&#xff0c;想要实现这个功能的小伙伴需要完成几个前置条件&#xff1a; 有一个GitHub账号安装了git&#xff0c;并可以通过git推送commit到GitHub上完成第一篇文章…

OpenHarmony的分布式服务框架介绍与实现解析

OpenHarmony的分布式服务框架是一个用于实现设备间高效协作与资源共享的重要架构&#xff0c;以下是其详细介绍&#xff1a; 框架概述 OpenHarmony的分布式服务框架基于分布式软总线、分布式数据管理、分布式Profile等技术特性&#xff0c;构建了统一的分布式服务管理机制&am…

360pika—弹性 KV 数据存储系统入门安装使用

一、简介 github官网说Pika 是一个高性能、大容量、多租户、数据持久化的弹性 KV 数据存储系统,使用 RocksDB 作为存储引擎。它完全兼容 Redis 协议,并支持其常用的数据结构,如字符串/哈希/列表/有序集合/集合/地理位置/HyperLogLog/发布-订阅/位图/数据流等。 二、对标啥能干…

springboot中使用gdal将表中的空间数据转shapefile文件

springboot中使用gdal将表中的空间数据转shapefile文件 代码&#xff1a; // 样本导出-将样本表导出为shapefile&#xff0c;复制样本shp文件到临时目录下 sampleDir是文件夹pathpublic void setYbShapeFile(Yb yb, File sampleDir) {// 创建 前时项 和 后时项 文件夹File y…

【学习笔记】蒙特卡洛与强化学习

视频链接&#xff1a;https://www.bilibili.com/video/BV1SV4y1i7bW 文章目录 [蒙特卡洛方法] 02 重要性采样&#xff08;importance sampling&#xff09;及 python 实现Basics实现重要性采样 [蒙特卡洛方法] 03 接受/拒绝采样&#xff08;accept/reject samping&#xff09;初…

查看MySQL存储引擎方法,表操作

修改数据库表存储引擎 show create table dept; show table status from itpux where name s2\G; select * from information_schema.TABLES where table_schemaitpux and table_names3; 查询整个mysql里面存储引擎是innodb/myisam的表 建表时候要写好存储引擎 -- 创建表 -- 表…

项目亮点案例

其实对我来说是日常操作&#xff0c;但是如果在面试的时候面试者能把日常的事情总结好发出来&#xff0c;其实足矣。 想让别人认同项目&#xff0c;选取的示例需要包含以下要素&#xff1a; 亮点项目四要素&#xff1a;明确的目标&#xff0c;问题点&#xff0c;解决方法和结果…

MyBatis通过注解配置执行SQL语句原理源码分析

文章目录 前置准备流程简要分析配置文件解析加载 Mapper 接口MapperAnnotationBuilder解析接口方法注解parseStatement 方法详解MapperBuilderAssistant 前置准备 创建一个mybatis-config.xml文件&#xff0c;配置mapper接口 <mappers><!--注解配置--><mapper…

蓝桥杯物联网开发板硬件组成

第一节 开发板简介 物联网设计与开发竞赛实训平台由蓝桥杯大赛技术支持单位北京四梯科技有限公司设计和生产&#xff0c;该产品可用于参加蓝桥杯物联网设计与开发赛道的竞赛实训或院校相关课程的 实践教学环节。 开发板基于STM32WLE5无线微控制器设计&#xff0c;芯片提供了25…

常用矢量图标库

常用矢量图标库 1. iconfont 阿里巴巴旗下的矢量图标素材库&#xff1b;很强大且图标内容很丰富的矢量图标库,提供矢量图标下载&#xff08;AI / SVG / PNG / 代码格式&#xff09;、在线存储等功能&#xff0c;支持按路径改变 icon 颜色。 iconfont 网址 设备图标 2. IconP…

Unity动态读取外部图片转Texture2D,内存过大问题解决方案

问题描述 加载原始图片2.63M的图片,分辨率为3023*4032,占用内存108.5M 加载原始图片12.6 M的图片,分辨率为6000*8000,占用内存427.2M 太恐怖了吧 解决方案 1.加载完图片,等比缩放,宽高改为1024或者512以下 1024占用5.2M,512占用1.3M,相比小了很多 2.原始Texture2…

在Visual Studio 2022中配置C++计算机视觉库Opencv

本文主要介绍下载OpenCV库以及在Visual Studio 2022中配置、编译C计算机视觉库OpenCv的方法 1.Opencv库安装 ​ 首先&#xff0c;我们需要安装OpenCV库&#xff0c;作为一个开源库&#xff0c;我们可以直接在其官网下载Releases - OpenCV&#xff0c;如果官网下载过慢&#x…

【AIGC】ChatGPT 结构化 Prompt 的高级应用

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;标识符的使用&#xff08;Use of Identifiers&#xff09;1. #2. <>3. - 或 4. [] &#x1f4af;属性词的重要性和应用应用场景 &#x1f4af;具体模块…

git使用和gitlab部署

1.ci,cd,DevOps ci&#xff1a;持续集成&#xff1a;开发的代码集成到代码仓库 cd&#xff1a;持续交互&#xff1a;从代码仓库拉取代码到部署到测试环境 cd&#xff1a;持续部署&#xff1a;从代码仓库拉取代码到部署到生产环境 DevOps:开发写完的代码自动集成&#xff0c…