适配器模式:接口转换的艺术,让不匹配成为过去式

news2025/1/19 19:15:32

适配器模式(Adapter Pattern)是一种结构型设计模式,它通过将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以一起工作。在Java中,适配器模式可以通过实现一个适配器类来实现两个不兼容接口之间的转换。

各角色定义

在适配器模式中,通常会涉及以下四种角色:

  1. 目标(Target)
    定义客户端所期望的接口。可以是具体的类或者抽象类。
  2. 适配者(Adaptee)
    拥有一个已经存在的接口,该接口与目标接口不兼容。这个已有的接口通常是一个没有继承和实现关系的旧接口。
  3. 适配器(Adapter)
    充当适配器的角色,实现目标接口。
    持有适配者的实例,通过适配者来实现目标接口的方法。负责将适配者的功能转换为目标接口期望的形式。
  4. 客户端(Client)
    使用目标接口来调用适配器的方法。客户端只知道目标接口,并不知道适配器和适配者的存在。

以上如图所示:
在这里插入图片描述

  • Target类表示目标接口,它有一个request()方法。
  • Adaptee类表示已有的不兼容接口,它有一个specificRequest()方法。
  • Adapter类是适配器,它实现了Target接口,并持有一个Adaptee实例。在request()方法中,调用Adaptee的specificRequest()方法来实现适配。

具体示例

下面我们介绍使用适配器来播放不同类型的音频文件的代码示例:

  1. 定义客户端需要的接口,比如播放指定类型的音频文件,入参是文件类型和文件名称:
public interface MediaPlayer {
    void play(String audioType, String fileName);
}
  1. 一个已有的接口(Adaptee)和实现类:
public interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // Do nothing
    }
}

public class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // Do nothing
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}
  1. 创建适配器类(Adapter),实现目标接口,并持有已有接口的实例:
public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMediaPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer.playMp4(fileName);
        }
    }
}
  1. 使用适配器模式
public class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;

    @Override
    public 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");
        }
    }
}

应用场景

适配器模式适用于以下场景:

当需要在一个已有系统中引入新的功能或者接口时,它与系统的目标接口不兼容,但又不能修改原有代码时,可以使用适配器模式。例如在一个数据库操作系统中,如果想要支持多种类型的数据库源,但系统只提供了一个固定类型数据库源的操作接口时,可以使用一个数据库源操作适配器来将不同类型数据库源转换成统一类型数据库源。
当需要在多个独立开发的系统或者组件之间进行协作时,但由于各自采用了不同的接口或者协议时,可以使用适配器模式。例如在一个分布式服务系统中,如果想要让不同语言编写的服务之间进行通信和调用,但各自采用了不同的通信协议和数据格式时,可以使用一个服务通信适配器来将不同协议和数据格式转换成统一协议和数据格式。

优点

适配器模式可以增强程序的可扩展性,通过使用适配器,可以在不修改原有代码的基础上引入新的功能或者接口。
适配器模式可以提高类的复用性,通过使用适配器,可以将已有的类或者接口重新组合和封装,使其符合新的需求。
适配器模式可以增加类的透明度,通过使用适配器,客户端只需要关注目标接口,而无需了解被适配者的具体实现。
适配器模式可以灵活地切换不同的被适配者,通过使用不同的适配器,可以动态地选择不同的被适配者来满足不同的场景。

缺点

适配器模式会增加系统的复杂性,过多地使用适配器会使系统变得零乱和难以理解。
适配器模式可能会降低系统的性能,因为每次调用目标接口时都需要经过适配器的转换。
适配器模式可能会违反开闭原则,如果目标接口发生变化,则需要修改所有的适配器类。

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

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

相关文章

第七篇:SQL语法-DML-数据操作语言

DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增删改操作。它主要包含以下操作, 添加数据(INSERT)修改数据(UPDATE)删除数据(DELETE) 一,添加数据(INSERT) 注意: 插入数据时&#xff0c…

云原生之基石-Docker Compose

1. 前言 在上一篇文章中介绍了基本的Docker工具,我们对单个应用程序进行单机单进程部署,制作Dockerfile文件,执行docker build来生成docker镜像, 执行docker run来运行一个容器,自己指定需要的参数如-v,但是…

在Ubuntu22.04上部署FoooCUS2.1

Fooocus 是一款基于 Gradio的图像生成软件,Fooocus 是对 Stable Diffusion 和 Midjourney 设计的重新思考: 1、从 Stable Diffusion 学习,该软件是离线的、开源的和免费的。 2、从 Midjourney 中学到,不需要手动调整,…

【AI】安装ubuntu20.04教程(未完待续)

目录 1 制作ubuntu20.04系统盘1.1 下载ubuntu镜像1.2 使用ultraiso写入镜像 2 安装Ubuntu系统 1 制作ubuntu20.04系统盘 1.1 下载ubuntu镜像 在清华镜像站https://mirrors.tuna.tsinghua.edu.cn/下载ubuntu20.04镜像 路径为/ubuntu-releases/20.04/,下载ubuntu-20…

【教程】C++语言基础学习笔记(七)——Array数组

写在前面: 如果文章对你有帮助,记得点赞关注加收藏一波,利于以后需要的时候复习,多谢支持! 【C语言基础学习】系列文章 第一章 《项目与程序结构》 第二章 《数据类型》 第三章 《运算符》 第四章 《流程控制》 第五章…

Promise与async await的作用及应用场景

在Web前端开发中,处理异步操作是非常常见的需求。为了解决这个问题,ES6引入了Promise和后续的async await。本文将介绍Promise和async await的作用,以及在实际开发中的应用场景。 一、Promise的作用及应用场景 Promise是一个表示异步操作最…

【MySQL】学习约束和使用图形化界面创建表

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-iqtbME2KmWpQFQSt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

综合例题及补充

目录 查询员工的编号、姓名、雇佣日期,以及计算出每一位员工到今天为止被雇佣的年数、月数、天数 计算出年 计算月 计算天数 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 查询员工的编号、姓名、雇佣日期&#xff0c…

S32 Design Studio的PE工具

S32 Design Studio软件是NXP公司专门为了方便用户开发S32K1系列芯片的IDE,跟Eclipse比较像。里面有个配套的图形工具Processor Expert,会产生一个后缀名为pe的文件,跟ST的cubemx作用类似。 双击pe文件即可打开pe界面,生成的文件将…

Codeforces Round 925 (Div. 3)

Codeforces Round 925 (Div. 3) Codeforces Round 925 (Div. 3) A. Recovering a Small String 题意:给出一个整数n,为三个26个字母的位置序号的和,输出字典序最小的三个字符的字符串。 思路:直接倒推,顺一遍&…

第6个-滚动动画

Day 6 - Scroll Animation 1. 演示效果 2. 分析思路 布局 所有的内容进行水平垂直居中,可以使用**margin:0 auto;,也可以使用flex**布局: body {background-color: #efedd6;display: flex;flex-direction: column;justify-content: center…

腾讯云幻兽帕鲁服务器配置怎么选择合适?

腾讯云幻兽帕鲁服务器配置怎么选?根据玩家数量选择CPU内存配置,4到8人选择4核16G、10到20人玩家选择8核32G、2到4人选择4核8G、32人选择16核64G配置,腾讯云百科txybk.com来详细说下腾讯云幻兽帕鲁专用服务器CPU内存带宽配置选择方法&#xff…

音视频剪辑|FFMPEG|windows10下的音视频格式转换,遮挡填充,GIF动图制作,背景音频抽取,替换

前言: 最近对于音视频和图像的处理问题比较感兴趣,但发现很多目前需要的功能要么需要付费但不会过于麻烦,要么比较麻烦,很可能某个功能实现需要安装很多软件 例如,视频转GIF动图,该功能的实现要么使用Pho…

VMware清理拖拽缓存 Ubuntu硬盘情况占用分析

这两天在尝试编译Linux源码,我在win上将源码下载下来然后复制到ubuntu上,这一步我粗略看到了三种方法:安装VM tools,就可以使文件正常的在win和ubuntu中复制剪切;使用scp命令将win和linux系统链接起来;使用…

P5440 【XR-2】奇迹 (大模拟dfs+欧拉筛板子+闰年)

传送门https://www.luogu.com.cn/problem/P5440 相信奇迹的人,本身就和奇迹一样了不起。——笛亚 《星游记》 思路历程:很离谱的一题,在理论上并不困难,只要简单dfs欧拉筛就能过。在一开始,我采用了倒着模拟的思路&am…

JavaWeb:关于登录认证的简单拓展

前提介绍 本文基于文章-------JavaWeb:SpringBootWeb登录认证 --黑马笔记 -------再做简单拓展 如果没有关于登录认证知识的基础,可以先看上面所说的的文章,文章在专栏javaweb中,下面我为了大家观看,直接放了链接。…

服务降级(Sentinel)

服务降级 采用 SentinelResource 注解方式实现, 必要的 依赖必须引入 以及 切面Bean 接口代码 RequestMapping("/degrade")SentinelResource(value DEGRADE_RESOURCE_NAME, blockHandler "blockHandlerForDegrade",entryType EntryType.IN…

Excel模板2:进度条甘特图

Excel模板2:进度条甘特图 ‍ 今天复刻B站up【名字叫麦兜的狗狗】的甘特图:还在买Excel模板吗?自己做漂亮简洁的甘特图吧!_哔哩哔哩_bilibili 阿里网盘永久分享:https://www.alipan.com/s/cXhq1PNJfdm 当前效果&…

2.13 数组练习

1、选择题 1.1、若有定义语句:int a[3][6]; ,按在内存中的存放顺序,a 数组的第10个元素是 B A)a[0][4] B) a[1][3] C)a[0][3] D)a[1][4] 解析:二维数组在内存中是以行优先的方式存放的。这意味着首先填充第一行的…

Excel练习:折线图突出最大最小值

Excel练习:折线图突出最大最小值 ​​ 要点:NA值在折现图中不会被绘制,看似一条线,实际是三条线。换成0值和""都不行。 ‍ 查看所有已分享Excel文件-阿里云 ‍ 学习的这个视频:Excel折线图&#xff0c…