Java设计模式-结构型模式-适配器模式

适配器模式

  • 适配器模式
    • 应用场景
    • 案例
    • 类适配器模式
    • 对象适配器模式
    • 接口适配器模式
    • 适配器模式在源码中的使用

适配器模式

在这里插入图片描述
如图:国外插座标准和国内不同,要使用国内的充电器,就需要转接插头,转接插头就是起到适配器的作用

适配器模式,是将某个类的接口转化为客户端期望的另一个接口表示,主要的目的是解决兼容性问题,让原本不匹配不能一起工作的两个类可以协同工作

应用场景

  1. 集成旧系统:当引入新系统时,通常需要与现有的旧系统进行集成。适配器模式可以帮助将新系统的接口适配成旧系统所期望的接口,从而实现两个系统之间的兼容性。例如,将新的支付系统接口适配成与旧的支付系统兼容的接口。

  2. 类库适配:当使用第三方类库时,有时需要将其接口适配成符合自己项目需求的接口。适配器模式可以用来封装第三方类库的接口,使其与项目代码无缝集成。例如,将不同数据库操作类库的接口适配成统一的数据库操作接口。

  3. 跨平台兼容:在跨平台开发中,不同平台可能有不同的接口和实现方式。适配器模式可以帮助将不同平台的接口适配成统一的接口,从而提供跨平台的兼容性。例如,将移动应用在不同操作系统上的界面适配成统一的用户界面。

  4. 日志记录器:在应用中使用不同的日志记录库时,可以使用适配器模式将它们的接口适配成统一的接口,以便在应用中无缝切换不同的日志记录库。

  5. 第三方API集成:当与第三方API进行集成时,可能需要将第三方API的接口适配成符合自己应用的接口规范。适配器模式可以帮助实现与第三方API的集成,并提供统一的接口给应用程序使用。

适配器模式有三种实现方式:类适配器模式、对象适配器模式、接口适配器模式

案例

已知家用电是220V的交流电,类如下,可以提供220V的电压

public class HouseholdElectricity220V {/*** 输出220V电压* @return*/public int output220V(){return 220;}
}

而我的手机需要使用5V的直流电,设立目标接口

public interface MobileElectricity {int output5V();int output10V();
}

我的需求是:我要给手机充电!
那么有两条路可以选择:

  1. 我去和供电站商量,开一条5V直流电的通路,我直接连上充电
  2. 我开发一个适配器,把220V电压转为手机需要的5V直流电
    很明显,只能使用方法2,开发一个适配器。
    通过上述案例,应该可以体会到什么场景下需要使用适配器模式了
  3. 原始接口复杂且稳定,且与新需求有关联。可以通过适配器模式简化开发
  4. 新的需求需要兼容老的需求
    不废话了
    下面分别使用 类适配器模式、对象适配器模式、接口适配器模式 实现该电源适配器

类适配器模式

类适配器模式就是 通过继承 被适配者类 ,来实现适配器兼容
适配器实现如下:

public class MobileAdapter5VClass extends HouseholdElectricity220V implements MobileElectricity{@Overridepublic int output5V() {super.output220V();/*变压操作*/System.out.println("开始变压220V->5V");System.out.println("输出5V");return 5;}@Overridepublic int output10V() {super.output220V();/*变压操作*/System.out.println("开始变压220V->10V");System.out.println("输出10V");return 10;}
}

通过继承 被适配的 类,将被适配类和目标接口关联起来
测试代码如下:

/*** 类适配器模式*/
@Test
public void adapterClassTest(){MobileAdapter5VClass adapter = new MobileAdapter5VClass();adapter.output5V();
}
输出:
输出220V电压
开始变压220V->5V
输出5V

因为依赖类的继承来实现,自然耦合性较高,违反了合成复用原则(尽量多使用组合、聚合,少使用继承)

想要降低耦合性,就要使用组合的方式,实现适配器,即:对象适配器模式

对象适配器模式

通过聚合 被适配的类 来实现 适配器
直接看代码:

public class MobileAdapter5VObject implements MobileElectricity{private final HouseholdElectricity220V electricity220V;public MobileAdapter5VObject(HouseholdElectricity220V householdElectricity220V) {this.electricity220V = householdElectricity220V;}@Overridepublic int output5V() {electricity220V.output220V();/*变压操作*/System.out.println("开始变压220V->5V");System.out.println("输出5V");return 5;}@Overridepublic int output10V() {electricity220V.output220V();/*变压操作*/System.out.println("开始变压220V->10V");System.out.println("输出10V");return 10;}
}
/*** 对象适配器模式*/
@Test
public void adapterObjectTest(){HouseholdElectricity220V electricity220V = new HouseholdElectricity220V();MobileAdapter5VObject adapter = new MobileAdapter5VObject(electricity220V);adapter.output5V();
}
输出:
输出220V电压
开始变压220V->5V
输出5V

看到这里,大家应该发现一个问题,我的目标接口有两个方法,output5V() 和 output10V()
而 output5V() 才是我本次需求所需要的,但是因为接口的限制,在实现适配器的时候,又不得不重写
output10V() 方法。这样的代码一点也不优雅,而且封装性不好。
有什么解决办法呢?
想一想,上一步我们把被适配 类 和 适配器类进行了解耦,那么能不能把 目标接口 和适配器也解耦呢
所以 就有了 接口适配器模式
可以使用抽象类 先继承 目标接口,并重写接口方法为空方法。适配器只和抽象类交互,只实现自己需要的方法。

接口适配器模式

接口的适配器是这样的:接口中往往有多个抽象方法,但是我们写该接口的实现类的时候,必须实现所有这些方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些.

当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可
直接看代码:

/**
*	抽象适配器类
*/
public abstract class AbsMobileAdapter implements MobileElectricity{@Overridepublic int output5V() {throw new RuntimeException("请先重写");}@Overridepublic int output10V() {throw new RuntimeException("请先重写");}
}/*********************************************************************************/
/*** 接口适配器类**/
public class MobileAdapter5VInterface extends AbsMobileAdapter{private final HouseholdElectricity220V electricity220V;public MobileAdapter5VInterface(HouseholdElectricity220V electricity220V) {this.electricity220V = electricity220V;}@Overridepublic int output5V() {electricity220V.output220V();/*变压操作*/System.out.println("开始变压220V->5V");System.out.println("输出5V");return 5;}
}

适配器模式在源码中的使用

  1. JDBC驱动程序:不同的数据库提供商实现了不同的JDBC驱动接口,使用适配器模式可以将这些不同的接口适配为标准的JDBC接口,提高应用程序的可移植性。
  2. 日志框架:Java中有多个常用的日志框架,如Log4j、SLF4J等,不同的日志框架提供的API不同,使用适配器模式可以将这些不同的API适配为一个统一的接口,方便再程序中进行日志记录和管理。
  3. 第三方库或SDK:在使用第三方库或 SDK 时,可能由于它们实现的 API 不同而导致应用程序复杂,使用适配器模式可以将不同的 API 适配为统一的接口,简化应用程序的调用。

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

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

相关文章

springboot国际化

1.环境配置 这里插入图片描述](https://img-blog.csdnimg.cn/024d6bc95623485eb6da4d998a892458.png) 2.文件配置 第一个默认环境 第二个英文环境 第三个中文环境 3.变量配置 调整语言 原理: 找到MessageSourceAutoConfiguration 中的 利用代碼的方式獲取国…

图论11-欧拉回路与欧拉路径+Hierholzer算法实现

文章目录 1 欧拉回路的概念2 欧拉回路的算法实现3 Hierholzer算法详解4 Hierholzer算法实现4.1 修改Graph,增加API4.2 Graph.java4.3 联通分量类4.4 欧拉回路类 1 欧拉回路的概念 2 欧拉回路的算法实现 private boolean hasEulerLoop(){CC cc new CC(G);if(cc.cou…

数字化转型时代,商业智能BI到底是什么?

据国际数据公司(IDC)预测,2025年时中国产生的数据量预计将达48.6ZB,在全球中的比例为27.8%。商业智能BI这一专为企业提供服务的数据类解决方案,仅2021年上半年在中国商业智能BI市场规模就达到了3.2亿美元,商…

java入门,从CK导一部分数据到mysql

一、需求 需要从生产环境ck数据库导数据到mysql,数据量大约100w条记录。 二、处理步骤 1、这里的关键词是生产库,第二就是100w条记录。所以处理数据的时候就要遵守一定的规范。首先将原数据库表进行备份,或者将需要导出的数据建一张新的表了…

Java绘图-第19章

Java绘图-第19章 1.Java绘图类 1.1Graphics类 Graphics类是用于绘制图形的抽象类,它是java.awt包中的一部分。Graphics类提供了各种方法,可以在图形上绘制各种形状、文本和图像。这些方法包括画线、画矩形、画椭圆、画弧、绘制图像等。 1.2Graphics2…

Android修行手册 - 阴影效果的几种实现以及一些特别注意点

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC 👉关于作者 专…

3D造型渲染软件DAZ Studio mac中文版介绍

DAZ Studio mac是一款3D造型和渲染软件,由 Daz 3D 公司开发。它允许用户创建、编辑、动画化并渲染精美的数字图像与动画。DAZ Studio 还提供了一个虚拟的3D艺术家工作室环境,让用户可以轻松地设置场景、布置角色和应用材质。 用户可以通过 DAZ Studio 中…

8.查询数据

一、单表查询 MySQL从数据表中查询数据的基本语为SELECT语。SELECT语的基本格式是: SELECT {* | <字段列名>} [ FROM <表 1>, <表 2>… [WHERE <表达式> [GROUP BY <group by definition> [HAVING <expression> [{<operator>…

032-从零搭建微服务-定时服务(一)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;mingyue: &#x1f389; 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心 源…

C语言不可不敲系列:跳水比赛排名问题

目录 1题干&#xff1a; 2解题思路&#xff1a; 3代码: 4运行结果: 5总结: 1题干&#xff1a; 5位运动员参加了10米台跳水比赛&#xff0c;有人让他们预测比赛结果 A选手说&#xff1a;B第二&#xff0c;我第三&#xff1b; B选手说&#xff1a;我第二&#xff0c;E第四&am…

十九章总结

Graphics类 Graphics类是所有图形上下文的抽象基类&#xff0c;封装了Java支持的基本绘图操作所需的状态信息&#xff0c;主要包括颜色、字体、画笔 Graphics2D类 Graphics2D类继承Graphics类实现功能更加强大的绘图操作集合 绘制图形 在项目中创建一个类&#xff0c;是该…

nginx安装搭建

下载 免费开源版的官方网站&#xff1a;nginx news Nginx 有 Windows 版本和 Linux 版本&#xff0c;但更推荐在 Linux 下使用 Nginx&#xff1b; 下载nginx-1.14.2.tar.gz的源代码文件&#xff1a;wget http://nginx.org/download/nginx-1.14.2.tar.gz 我的习惯&#xff0…

【Linux进阶之路】一文吃透文件

前言 先来谈一下文件的共识 文件 内容 属性。 解释&#xff1a;文件在创建时就有基本属性&#xff0c;比如权限&#xff0c;文件名&#xff0c;文件的创建时间等基本信息。文件分为打开的文件与未被打开的文件。 解释&#xff1a;打开的文件由操作系统进行管理。未打开的文件…

JZ22:链表中倒数第k个结点

JZ22&#xff1a;链表中倒数第k个结点 题目描述&#xff1a; 输入一个链表&#xff0c;输出该链表中倒数第k个结点。 示例1 输入&#xff1a; 1,{1,2,3,4,5} 返回值&#xff1a; {5} 分析&#xff1a; 快慢指针思想&#xff1a; 需要两个指针&#xff0c;快指针fast&…

云课五分钟-03第一个开源游戏复现-贪吃蛇

前篇 云课五分钟-02第一个代码复现-终端甜甜圈C 视频 云课五分钟-03第一个开源游戏复现-贪吃蛇 一个终端的动态字符显然很难调动编程的积极性&#xff0c;那么更有趣的开源的游戏也许是一种更好的启发。 文本 蓝桥ROS机器人之绚丽贪吃蛇 如何在Linux下使用 DungeonRush-mast…

【java学习—十四】反射机制调用指定方法、指定属性(5)

文章目录 1. 调用指定方法2. 调用指定属性 1. 调用指定方法 通过反射&#xff0c;调用类中的方法&#xff0c;通过 Method 类完成。步骤&#xff1a;     ①通过 Class 类的 getMethod(String name,Class...parameterTypes) 方法取得一个 Method 对象&#xff0c;并设置此…

C#使用时序数据库 InfluxDB

一、安装 https://docs.influxdata.com/influxdb/v2/install/?tWindows 解压后使用cmd运行 访问 localhost:8086 配置 第一次登入会初始化 配置登入账号 保存TOKEN 这个TOKEN用于后期代码链接访问数据库&#xff0c;忘记了只能删除重新生成 点击QUCK START进入管理页面 …

【vue实战项目】通用管理系统:api封装、404页

前言 本文为博主的vue实战小项目系列中的第三篇&#xff0c;很适合后端或者才入门的小伙伴看&#xff0c;一个前端项目从0到1的保姆级教学。前面的内容&#xff1a; 【vue实战项目】通用管理系统&#xff1a;登录页-CSDN博客 【vue实战项目】通用管理系统&#xff1a;封装to…

Android抓包工具—Fiddler详解

前言 平时和其他大佬交流时&#xff0c;总会出现这么些话&#xff0c;“抓个包看看就知道哪出问题了”&#xff0c;“抓流量啊&#xff0c;payload都在里面”&#xff0c;“这数据流怎么这么奇怪”。 &#x1f449;这里出现的名词&#xff0c;其实都是差不多的意思啊&#xf…

ElementUI表格el-table自适应高度(表头表尾固定不动)

ElementUI表格el-table自适应高度&#xff08;表头表尾固定不动&#xff09;&#xff0c;内容只在中间滚动&#xff0c;效果如图&#xff1a; 实现代码 <div class"mt-10" :style"{height:tableHeight}"><div class"operation-bar">…