GPT带我学-设计模式-适配器模式
1 什么是适配器设计模式
适配器设计模式是一种结构性设计模式,用于在不兼容的接口之间进行转换。它允许将一个类的接口转换成客户端所期望的接口。
适配器模式包含以下几个角色:
目标接口(Target):定义客户端所期望的接口。
适配器(Adapter):实现目标接口,同时持有被适配者的实例,将客户端的请求转发给被适配者。
被适配者(Adaptee):已存在的类或接口,不符合客户端的需求。
客户端(Client):通过适配器来调用被适配者的功能。
适配器模式可以解决以下问题:
在系统中使用已存在的类,但其接口与系统要求的接口不一致。
在客户端需要使用不可直接访问的类时,可以通过适配器来间接访问。
适配器模式的优点包括:
可以重新使用已存在的类,不需要修改其源代码。
提供了灵活性,可以在系统中引入新的类。
然而,适配器模式也存在一些缺点:
引入了一个额外的结构,增加了系统的复杂度。
可能会导致系统的性能下降。
总体而言,适配器设计模式是一种实现接口转换的方法,可以在不改变现有代码的情况下使不兼容的接口能够协同工作。
2 适配器模式有几种形式?
适配器模式有两种形式:
类适配器模式:这种形式下,适配器类继承自已存在的类,并同时实现目标接口。适配器类通过继承已存在的类,使得目标接口与被适配者接口能够兼容。类适配器模式使用多重继承实现,因此只适用于支持多重继承的编程语言。
对象适配器模式:这种形式下,适配器类持有被适配者的实例,并实现目标接口。适配器类通过调用被适配者的方法来完成客户端的请求。对象适配器模式使用组合(对象持有)实现,因此可以适用于任何支持对象组合的编程语言。
无论是类适配器模式还是对象适配器模式,其目的都是为了将被适配者的接口转换成目标接口。选择哪种形式取决于所用编程语言的特性以及具体的应用场景。
3 请用java举一个实际的例子帮助我理解适配器模式
假设我们有一个音乐播放器程序,它能够播放MP3格式的音乐文件。现在我们引入了一个新的音乐库,它提供了一些高质量的WAV格式音乐文件,但是我们的音乐播放器只能播放MP3格式的文件。这时,我们可以使用适配器模式来解决兼容性问题。
首先,我们需要定义目标接口,即音乐播放器所期望的接口:
public interface MediaPlayer {void play(String fileName);
}
然后,我们实现一个MP3播放器类,负责播放MP3格式的音乐文件:
public class Mp3Player implements MediaPlayer {@Overridepublic void play(String fileName) {System.out.println("Playing MP3 file: " + fileName);}
}
接下来,我们需要适配器类来将WAV文件适配为MP3格式。适配器类会实现目标接口,并持有被适配者的实例:
public class WavToMp3Adapter implements MediaPlayer {private WavPlayer wavPlayer;public WavToMp3Adapter(WavPlayer wavPlayer) {this.wavPlayer = wavPlayer;}@Overridepublic void play(String fileName) {wavPlayer.playWav(fileName);}
}
被适配者类WavPlayer负责播放WAV格式的音乐文件:
public class WavPlayer {public void playWav(String fileName) {System.out.println("Playing WAV file: " + fileName);}
}
最后,我们可以在客户端代码中使用适配器模式来播放不同格式的音乐文件:
public class Client {public static void main(String[] args) {MediaPlayer mp3Player = new Mp3Player();MediaPlayer wavPlayer = new WavToMp3Adapter(new WavPlayer());mp3Player.play("song.mp3"); // 播放MP3文件wavPlayer.play("song.wav"); // 使用适配器,播放WAV文件}
}
执行结果
Playing MP3 file: song.mp3
Playing WAV file: song.wav
客户端代码中,我们可以看到通过适配器类,我们成功地播放了WAV格式的音乐文件。适配器模式帮助我们将不兼容的WAV文件适配为MP3文件,使得我们的音乐播放器能够正常播放不同格式的音乐文件。
4 适配器模式主要应用在哪些场景
适配器模式主要应用于以下场景:
将旧接口适配成新接口:当需要使用一个已经存在的类,但是它的接口与你的需求不兼容时,可以使用适配器模式。适配器将旧接口转换为目标接口,使得客户端可以通过目标接口调用旧接口的功能。
多个类的接口统一:当多个类具有不同的接口,但需要以统一的方式使用它们时,可以使用适配器模式。适配器模式可以将这些类的接口适配成一个统一的接口,使得客户端可以一致地调用它们。
封装外部依赖:当需要与外部的组件或库进行交互,并且想要将其隐藏在自己的代码中时,可以使用适配器模式。适配器模式可以封装对外部依赖的调用,使得客户端无需直接与外部依赖进行交互。
兼容新旧版本:当需要兼容不同版本的组件或库时,可以使用适配器模式。适配器可以根据不同的版本提供不同的实现,使得客户端能够适应不同的版本。
总的来说,适配器模式的主要目的是解决接口不兼容的问题,使得不兼容的类能够协同工作。适配器模式可以帮助降低代码的耦合度,提高代码的复用性和可扩展性。
5 spring源码中在哪里使用了适配器模式?
在Spring源码中,有几个地方使用了适配器模式。
HandlerAdapter:Spring MVC框架中的HandlerAdapter接口及其实现类就是适配器模式的应用。它负责将请求分发给对应的Controller处理,并将结果返回给前端。Spring提供了多种HandlerAdapter的实现类,适配不同类型的Controller处理方式,如注解控制器、类层次结构控制器、同步和异步控制器等。
MessageListenerAdapter:Spring的消息驱动模块中,MessageListenerAdapter就是一个适配器模式的实例。它将底层的消息监听器(如javax.jms.MessageListener)适配成一个特定的Spring MessageListener,使得底层监听器能够在Spring消息驱动容器中被使用。
DefaultAdvisorAdapterRegistry:Spring AOP模块中的AdvisorAdapter就是适配器模式的应用。Spring AOP中使用Advisor和Advice来实现方法拦截和增强,而AdvisorAdapter负责将不同类型的Advice适配成统一的Advisor接口实现类,以便统一管理。
这些都是Spring源码中使用适配器模式的一些例子,它们都用于将不同的接口适配成统一的接口,以便进行统一处理或使用。适配器模式在Spring中的应用帮助实现了框架的灵活性和扩展性。
相关文章:
GPT带我学-设计模式-适配器模式
1 什么是适配器设计模式 适配器设计模式是一种结构性设计模式,用于在不兼容的接口之间进行转换。它允许将一个类的接口转换成客户端所期望的接口。 适配器模式包含以下几个角色: 目标接口(Target):定义客户端所期望…...
Pyecharts教程(七):使用pyecharts创建堆叠柱状图的示例
Pyecharts教程(七):使用pyecharts创建堆叠柱状图的示例 作者:安静到无声 个人主页 目录 Pyecharts教程(七):使用pyecharts创建堆叠柱状图的示例完整代码推荐专栏在数据可视化中,柱状图是一种常见的图表类型,它可以清晰地展示各类别之间的比较关系。然而,如果我们想要在同…...
C++中的强制转换的常用类型及应用场景详解
C中的强制转换的常用类型及应用场景详解 文章目录 C中的强制转换的常用类型及应用场景详解一、静态转换(static_cast)二、动态转换(dynamic_cast)三、常量转换(const_cast)四、重新解释转换(rei…...
ubuntu调整时区
ubuntu在新装系统的时候,所用的时区不一定是8的时区,需要设置一下,否则执行cron等定时任务的时候,时间就会不对 查看当前系统的时区 date -R tzselect 选择时区,但是没用 ,作用可能就是 选择时区 设置时区:…...
mybatis:动态sql【2】+转义符+缓存
目录 一、动态sql 1.set、if 2.foreach 二、转义符 三、缓存cache 1. 一级缓存 2. 二级缓存 一、动态sql 1.set、if 在update语句中使用set标签,动态更新set后的sql语句,,if作为判断条件。 <update id"updateStuent" pa…...
2021年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试
第1题:抓牛 农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式: 1、从X移动到X-1或X+1,每次移动花费一分钟 2、从X移动到2*X,每次移动花费一分钟 假设牛没有意识到农夫的…...
Ansible学习笔记1
公司的服务器越来越多,维护一些简单的事情都会变得很繁琐。用Shell脚本来管理少量服务器效率还行,服务器多了,Shell脚本无法实现高效率运维。这种情况下,我们需要引入自动化运维工具,对多台服务器实现高效运维。 配置服…...
解决centos离线安装cmake找不到OpenSSL问题
安装方法:见另外一篇文章 https://blog.csdn.net/zhongxj183/article/details/118488629 按照文章下载了离线gcc 和OpenSSL,以及在cmake官网下载了最新版 cmake-3.27.4.tar.gz 顺利安装gcc 和OpenSSL 但执行编译cmake时,报错找不到OpenSSL…...
Java 中数据结构ArrayList的用法
Java ArrayList ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。 方法集合样例代码 import java.util.*;public class list_set_iterator {public static void main(String[] args) {Lis…...
UDP 多播(组播)
前言(了解分类的IP地址) 1.组播(多播) 单播地址标识单个IP接口,广播地址标识某个子网的所有IP接口,多播地址标识一组IP接口。单播和广播是寻址方案的两个极端(要么单个要么全部)&am…...
分布式环境集成JWT(Java Web Token)
目录 一,说明:二,Token、Session和Cookie比较三,Spring Boot项目集成JWT1,引入依赖2,Token工具类3,定义拦截器4,注册拦截器5,编写登录代码6,测试 四ÿ…...
Python实战之数据表提取和下载自动化
在网络爬虫领域,动态渲染类型页面的数据提取和下载自动化是一个常见的挑战。本文将介绍如何利用Pyppeteer库完成这一任务,帮助您轻松地提取动态渲染页面中的数据表并实现下载自动化。 一、环境准备 首先,确保您已经安装了Python环境。接下来…...
Midjourney学习(三)6个高级应用
使用Remix Mode在原图片的基础上进行二次创作 通过prompt得到大图之后,点击Make Variations按钮,输入Remix Prompt,即可得到意想不到的效果! 局部内容重绘 通过局部重绘可以实现对画面内容更加精细化的控制,同样也是需…...
C语言:指针类型的意义
1.指针的类型决定了解引用时访问几个字节 2.指针的类型决定了指针1、-1跳过几个字节 一、指针的类型决定指针解引用时访问几个字节 例如 int 型指针解引用时访问4个字节 char 型指针解引用时访问1个字节 详解代码如下: int b 0x11223344(十六进制&…...
如何将 PDF 转换为 Word:前 5 个应用程序
必须将 PDF 转换为 Word 才能对其进行编辑和自定义。所以这里有 5 种很棒的方法 PDF 文件被广泛使用,因为它非常稳定且难以更改。这在处理法律合同、财务文件和推荐信等重要文件时尤其重要。但是,有时您可能需要编辑 PDF 文件。最好的方法是使用应用程序…...
AP5192 DC-DC降压恒流LED汽车头灯摩托车电动车大灯电源驱动
AP5192是一款PWM工作模式,高效率、外围简单、 内置功率MOS管,适用于4.5-100V输入的高精度 降压LED恒流驱动芯片。最大电流1.5A。 AP5192可实现线性调光和PWM调光,线性调光 脚有效电压范围0.55-2.6V. AP5192 工作频率可以通过RT 外部电阻编程 来设定&…...
Python Opencv实践 - Canny边缘检测
import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_GRAYSCALE) print(img.shape)#图像Canny边缘检测 #cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradien…...
Python编程练习与解答 练习119:低于和高于平均水平
编写一个程序,从用户处读取数字,直到用户输入空行。程序应该显示用户输入的所有值的平均值。然后所有程序应该显示所有平均值的值,然后显示所有平均值(若有),最后显示所有高于平均值的值。再每个值列表之前…...
vue中的nextTick的作用
vue里面,常用的事件onMounted里,总喜欢用一个nextTick: onMounted(() > {nextTick(() > {init();}); });这个东西有啥用呢?我总搞不懂。 今天我忽然有点明白了。这是一个跟前面语句有关的方法。意思是,等前面的…...
如何通过四个步骤清理网络防火墙规则
组织必须确保适当的安全策略到位,以保护其投资并优化其安全有效性。然而,随着网络的扩展和复杂性的增加,网络运营团队面临着管理来自多个供应商的大量防火墙和网络设备的挑战。他们必须解决分散的基础设施、职能孤岛、人员配置问题、分散的管…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
