【设计模式】适配器模式(包装器模式),缺省适配器模式,双向适配器模式

适配器模式(Adapter Pattern)详解

一、适配器模式简介

适配器模式是一种结构型设计模式,它将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以协同工作。

简单来说,适配器模式就像是一个变压器或者转接头,它可以帮助我们解决两个不兼容接口之间的合作问题。

别名为**包装器(Wrapper)**模式。

定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。

二、适用场景与针对的问题

  • 适用场景:当你需要使用一个已有的类,但是它的接口并不符合你的需求时;或者你需要创建一个可复用的类,该类能够与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
  • 针对的问题:主要是解决不同接口之间的不兼容性问题,使得它们能够在不影响各自实现的情况下进行协作。

三、实际案例

想象一下,你有一台笔记本电脑和一部手机,两者都需要充电,但它们的充电插口不一样。如果你只有一个电源适配器,这个适配器能将家用电源转换为笔记本电脑所需的电压和电流类型,但对于手机则无法直接使用。此时,你就需要一个USB-C到Lightning的适配器来为你的手机充电。这里,电源适配器和USB-C到Lightning适配器就起到了适配器的作用。

3.1 适配器模式的结构与实现

适配器模式的结构(类适配器)
在这里插入图片描述

适配器模式的结构(对象适配器)
在这里插入图片描述
适配器模式的结构
适配器模式包含以下3个角色:
Target(目标抽象类)
Adapter(适配器类)
Adaptee(适配者类)

四、代码案例

假设有一个MediaPlayer接口和其实现类AudioPlayer,它只能播放mp3格式的音频文件。现在我们需要扩展其功能以支持更多格式如VLC和MP4,但不想改变原有的AudioPlayer类。这时就可以使用适配器模式。

// 目标接口
interface MediaPlayer {public void play(String audioType, String fileName);
}// 已有类,实现了不同的接口
class AdvancedMediaPlayer {public void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}public void playMp4(String fileName) {System.out.println("Playing mp4 file. Name: " + fileName);}
}// 适配器类
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new AdvancedMediaPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new AdvancedMediaPlayer();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);}}
}// 使用适配器的类
class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file. Name: " + fileName);} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 测试类
public class Test {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "beyond the horizon.mp3");audioPlayer.play("mp4", "alone.mp4");audioPlayer.play("vlc", "far far away.vlc");audioPlayer.play("avi", "mind me.avi");}
}

在这个例子中,MediaAdapter充当了适配器的角色,它将AdvancedMediaPlayer的功能适配到了MediaPlayer接口上,从而解决了接口不兼容的问题。通过这种方式,我们可以轻松地扩展AudioPlayer的功能,让它支持更多的音频格式。

五、缺省适配器模式

  • 定义:当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。
  • 结构
    在这里插入图片描述- 实现
    缺省适配器类的典型代码片段(C++):
abstract class AbstractServiceClass : ServiceInterface
{public void ServiceMethod1() {  }  //空方法public void ServiceMethod2() {  }  //空方法public void ServiceMethod3() {  }  //空方法
}

六、双向适配器模式

  • 结构
    在这里插入图片描述
  • 实现
public class Adapter : Target, Adaptee 
{//同时维持对抽象目标类和适配者的引用private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target;}public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}public void Request() {adaptee.SpecificRequest();}public void SpecificRequest() {target.Request();}
}

七、适配器模式的优缺点与适用环境

  • 模式适用环境:系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码
    创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作

  • 模式优点
    将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
    增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
    灵活性和扩展性非常好
    类适配器模式:置换一些适配者的方法很方便
    对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类

  • 模式缺点
    类适配器模式:(1) 一次最多只能适配一个适配者类,不能同时适配多个适配者;(2) 适配者类不能为最终类;(3) 目标抽象类只能为接口,不能为类
    对象适配器模式:在适配器中置换适配者类的某些方法比较麻烦

经典运用:
Sun公司在1996年公开了Java语言的数据库连接工具JDBC,JDBC使得Java语言程序能够与数据库连接,并使用SQL语言来查询和操作数据。JDBC给出一个客户端通用的抽象接口,每一个具体数据库引擎(如SQL Server、Oracle、MySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。抽象的JDBC接口和各个数据库引擎API之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的驱动程序。

部分内容由AI大模型生成,请注意识别!

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

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

相关文章

安全初级(一)

一.docker的搭建和VPN连接 1.输入指令:apt-get install docker.io docker-compose 2.设置docker代理:创建文件夹以及对应的文件 /etc/systemd/system/docker.service.d/http-proxy.conf 在该文件中配置自己的代理ip以及代理端口 [Service] Environme…

Java多线程:核心技术与实战指南

目录🚀前言🤔什么是多线程?💻创建线程💯创建方法一:继承Thread类💯创建方法二:实现Runnable接口💯创建方法三:实现Callable接口💯三种方法对比&am…

高斯代数基本定理的一种证明

代数基本定理 对于多项式 f(z)anznan−1zn−1⋯a1za0f(z) a_n z^n a_{n-1} z^{n-1} \cdots a_1 z a_0f(z)an​znan−1​zn−1⋯a1​za0​(其中 n>1n > 1n>1 且 an,a0≠0a_n, a_0 \neq 0an​,a0​0),它在复数域内有根。 f(z)U…

【K8S】Kubernetes 使用 Ingress-Nginx 基于 Cookie 实现会话保持的负载均衡

文章目录 1. 创建测试应用 Deployment3. 配置基于 Cookie 的 Ingress4. 部署与测试步骤(1) 应用配置(2) 获取 Ingress IP(3) 测试会话保持(4) 使用 Nginx 取消域名的限制(仅推荐测试使用)5、生产优化建议6、独立 Nginx 配置参考在现代微服务架构中,负载均衡是保证高可用的关…

2.查询操作-demo

在连接数据库的基础上步骤:Query-查询关闭查询db.Next()逐行输出,并指定到当前变量Scan-扫描rows, err : db.Query("SELECT id,server_ip FROM softswitch_server_info")package main//查询语句-demo //关键字-queryimport ("database/sq…

用OpenCV标定相机内参应用示例(C++和Python)

下面是一个完整的 使用 OpenCV 进行相机内参标定(Camera Calibration) 的示例,包括 C 和 Python 两个版本,基于棋盘格图案标定。一、目标:相机标定 通过拍摄多张带有棋盘格图案的图像,估计相机的内参&#…

(二)OpenCV——边缘增强与检测

边缘增强与检测是图像处理中的核心技术,其核心目标是突出图像中的不连续区域(边缘),为后续的图像分析提供基础。一、基本概念边缘本质上是图像中灰度/颜色发生突变的区域,对应着:物体边界表面方向改变材质变…

018 进程控制 —— 进程等待

🦄 个人主页: 小米里的大麦-CSDN博客 🎏 所属专栏: Linux_小米里的大麦的博客-CSDN博客 🎁 GitHub主页: 小米里的大麦的 GitHub ⚙️ 操作环境: Visual Studio 2022 文章目录进程控制 —— 进程等待1. 进程等待必要性2. 常用等待方法&#xf…

PHP password_hash() 函数

password_hash() 函数用于创建密码的散列(hash)PHP 版本要求: PHP 5 > 5.5.0, PHP 7语法string password_hash ( string $password , int $algo [, array $options ] )password_hash() 使用足够强度的单向散列算法创建密码的散列(hash&…

理解Linux文件系统:从物理存储到统一接口

目录 一、狭义理解(物理层面) 二、广义理解(Linux系统视角) 三、文件结构解析 四、系统实现机制 一、狭义理解(物理层面) 存储特性:文件以二进制形式存储在磁盘等永久性存储介质中 介质特点…

前端接入海康威视摄像头的三种方案

方案选择​方案适用场景优缺点​Web SDK(3.0)​​需要完整功能(PTZ控制、录像回放)功能全,但需加载海康JS文件​RTSP转Web播放​低延迟实时监控需后端转码(如FFmpeg转HLS)​HTTP API​简单截图或…

openGL学习(Shader)

认识Shader在计算机图形学中,Shader(着色器)是一种运行在 GPU(图形处理单元)上的程序,用于控制图形渲染过程中顶点和像素的处理。着色器是 OpenGL、Direct3D、Vulkan 等图形 API 的核心组成部分&#xff0c…

webpack高级配置

一、了解webpack高级配置: 1、什么是webpack高级配置: 进行 Webpack 优化,让代码在编译或者运行时性能更好 2、webpack优化从哪些方面入手: ① 提升开发体验,增强开发和生产环境的代码调试: 如果代码编写…

LLM表征工程还有哪些值得做的地方

LLM表征工程还有哪些值得做的地方 在大型语言模型(LLM)的表征工程领域,近年来涌现出多个具有突破性的创新方向,这些方法通过动态调整、多模态融合、结构化记忆增强等技术,显著提升了模型的适应性、可解释性和效率。 一、动态自适应表征:从静态到动态的范式革新 传统LL…

LabVIEW智能避障小车

​LabVIEW结合 NI、德州仪器(TI)、欧姆龙(Omron)等硬件,设计实现了一款具备智能避障、循迹功能的轮式机器人。系统支持手动操控与自主运行两种模式,通过无线通信实时传输传感器数据与图像信息,在…

逻辑代数中的基本规则,代入规则和反演规则,对偶规则

本文探讨了代入规则在逻辑等式中的应用,解释了如何通过替换变量来保持等式的正确性,同时介绍了反演规则和对偶规则的概念。代入规则定义:在任何一个包含变量A的逻辑等式中,如果用另一个逻辑式代入式中的所有A位置,则等式依然成立反…

Javaweb使用websocket,请先连上demo好吧!很简单的!

Javaweb使用websocket先看结构及效果MyWebSocketHandler用于处理消息WebSocketConfig用于配置建联地址等SchedulerConfig必须配置这个MyWebSocketInterceptor建联的拦截器SpringBootWebsocketApplication启动类POM依赖展示效果源码先看结构及效果 MyWebSocketHandler用于处理消…

文心大模型4.5开源测评:保姆级部署教程+多维度测试验证

前言:国产大模型开源的破局时刻 2025年6月百度文心大模型4.5系列的开源,标志着国产AI从"技术跟跑"向"生态共建"的关键跨越。 文心大模型4.5是百度自主研发的新一代原生多模态基础大模型,通过多个模态联合建模实现协同优…

前端学习5:Float学习(仅简单了解,引出flex)

一、Float基础概念1. 设计初衷: float最初是为实现文字环绕图片的效果(类似杂志排版),后来被开发者用来做页面布局。2. 核心特性:使元素脱离普通文档流(但仍在DOM中)元素会向左/右浮动&#xff…

08-自然壁纸实战教程-视频列表-云

08-自然壁纸实战教程-视频列表 前言 视频列表页面本质上也是一个数据展示的列表,不同之处在于之前是是展示壁纸,Image组件负责渲染,这里展示的是视频,使用Video组件,另外视频页面也实现了下载的基本功能,…