当前位置: 首页 > news >正文

适配器模式 Adapter Pattern

https://en.wikipedia.org/wiki/Adapter_pattern

https://www.baeldung.com/java-adapter-pattern

适配器模式(也称为包装器「wrapper」,与装饰器模式「decorator pattern」共享的另一种命名),它允许将现有类的接口用作另一个接口。它通常用于使现有类与其他类协同工作,而无需修改其源代码。

适配器模式描述了如何解决重复出现的「recurring」设计问题,以设计灵活和可重用的面向对象软件,即更容易实现、更改、测试和重用的对象。

解决了以下问题:

如何重用没有客户端所需接口的类?
具有不兼容「incompatible」接口的类如何协同工作?
如何为类提供替代接口「alternative interface」?


通常,一个(已经存在的)类不能被重用,只是因为它的接口不符合「conform to」客户端要求的接口。

如何解决这些问题:

定义一个单独的适配器类「adapter」,将类(adaptee)的(不兼容)接口转换为客户端所需的另一个接口(target)。

通过适配器「adapter」处理(重用)没有所需接口的类。

这种模式的关键思想是通过一个单独的适配器「adapter」来工作,该适配器在不更改的情况下调整(现有)类的接口。

客户端不知道他们是直接使用目标类,还是通过适配器使用没有目标接口的类。

另请参见下面的UML类图。

在上面的UML类图中,需要 target 接口的 client 类不能直接重用adaptee类,因为 adaptee 的接口不符合target 接口。相反,客户端通过一个 adapter 类工作,该类根据adaptee实现了target 接口:

对象适配器「object adapter 」方式通过在运行时委托给 adaptee 对象来实现 target 接口(adaptee.specificOperation())。

类适配器「class adapter」方式通过在编译时继承 adaptee 类来实现目标接口(specificOperation())。

Object adapter pattern

在这个适配器模式中,适配器包含它所包装的类的一个实例。在这种情况下,适配器会调用包装对象的实例。

下面这个图片描述了 Adapter 实现了 Target,包含一个 Adaptee 的引用。

Class adapter pattern

此适配器模式使用多个多态接口「polymorphic interfacesmultiple polymorphic interfaces」,实现或继承预期的接口预先存在的接口。通常将预期的接口创建为纯接口类,特别是在Java(JDK 1.8之前)等不支持类多重继承的语言中。

这了这个没有展示出,预期的接口 ,只展示了 预先存在的接口 Adaptee1-N。

所以来看看下图的解释,实现了(绿色箭头)预期的接口 ,继承了(蓝色箭头)预先存在的接口

继承是因为不一定对 adaptee 有控制权。 

OOP中的类之间关系-CSDN博客

Benefits and Trade-Offs

类适配器方法最适合Target和Adaptee方法之间的一对一映射。这样,我们就可以使用委托,而无需在Adapter中进行额外的实现。但是,如果Target接口更复杂,这种方法可能需要在Adapter中进行额外的工作。然而,我们可以通过委托「delegation」来解决这个问题:

在这里,我们只将request()方法委托给Adaptee。其余部分取自ConcreteTarget。我们可以使用组合将这些接口方法委托给实现,以避免代码重复。同时,如果我们不需要双边「two-way」适配器,我们可以使用对象适配器,这将使结构更简单:

因此,实现此模式的方式在很大程度上取决于代码库的初始状态,我们是否可以使用接口,以及我们是否需要为适配器提供在两种情况下工作的能力。

Adapter Pattern Example

Java有一个很好的适配器模式示例,我们可以在这里查看。Enumeration 和 Iterator 是两个相关的接口,是adapter-adaptee 关系的很好的例子。

public interface Enumeration<E> {boolean hasMoreElements();E nextElement();default Iterator<E> asIterator() {return new Iterator<>() {@Override public boolean hasNext() {return hasMoreElements();}@Override public E next() {return nextElement();}};}}

Iterator接口的描述包含以下内容:

        iterator 用来遍历 collection。iterator在Java集合框架中取代了Enumeration。Iterators 与Enumerations 有两个不同之处:

        Iterators 允许调用者在迭代过程中使用定义良好的语义从底层集合中删除元素。

        方法名称已得到改进。

从技术上讲,枚举具有相同的接口,唯一的区别是方法名称:

public interface Iterator<E> {boolean hasNext();E next();default void remove() {throw new UnsupportedOperationException("remove");}default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());}}

Adapter Implementations

正如我们所看到的,这些接口是相似的,具有相同的目标。默认的asIterator()方法是在Java 9中添加的,它包含使用匿名类实现Adapter模式:

default Iterator<E> asIterator() {return new Iterator<>() {@Override public boolean hasNext() {return hasMoreElements();}@Override public E next() {return nextElement();}};
}

这个例子使用了组合,但在这种情况下并不明确。我们不将枚举实例传递给迭代器,因为我们在枚举的上下文中创建了迭代器。这样,我们就可以直接访问Enumeration方法。这是一种非常强大的技术,它允许隐藏接口的一部分并使用委托给私有方法。前面的类和对象适配器示例需要公共API进行委派。

然而,只有当我们同时控制adapter 和 adaptee 时,才有可能使用匿名类实现Adapter模式,而这在大多数情况下是不可能的。让我们想象一下,在Java 9之前,我们如何实现相同的功能:

public class IteratorAdapter<E> implements Iterator<E> {private Enumeration<E> enumeration;public IteratorAdapter(Enumeration<E> enumeration) {this.enumeration = enumeration;}@Overridepublic boolean hasNext() {return enumeration.hasMoreElements();}@Overridepublic E next() {return enumeration.nextElement();}}

此示例与我们之前回顾的对象适配器示例相同。让我们用类适配器实现相同的功能。我们将在这个例子中使用StringTokenizer,因为它实现了枚举接口:

public class StringTokenizer implements Enumeration<Object>
public class StringTokenizerIteratorAdapter extends StringTokenizer implements Iterator<String> {public StringTokenizerIteratorAdapter(final String str, final String delim, final boolean returnDelims) {super(str, delim, returnDelims);}public StringTokenizerIteratorAdapter(final String str, final String delim) {super(str, delim);}public StringTokenizerIteratorAdapter(final String str) {super(str);}@Overridepublic boolean hasNext() {return hasMoreTokens();}@Overridepublic String next() {return nextToken();}
}

我们创建了一个双向「 two-way」适配器(相当于实现了 Enumeration 和 Iterator 两个接口),可以用作迭代器和StringTokenizer。迭代器方法不直接委托给枚举器中的方法,而是委托给StringTokenizer中更具体的方法。

相关文章:

适配器模式 Adapter Pattern

https://en.wikipedia.org/wiki/Adapter_pattern https://www.baeldung.com/java-adapter-pattern 适配器模式&#xff08;也称为包装器「wrapper」&#xff0c;与装饰器模式「decorator pattern」共享的另一种命名&#xff09;&#xff0c;它允许将现有类的接口用作另一个接…...

Android 动态加入Activity 时 manifest 注册报错解决。使用manifestPlaceholders 占位

需求如下&#xff1a; 项目 测试demo 有多个渠道&#xff0c;部分渠道包含支付功能&#xff0c;在主测试代码外&#xff0c;需要一个单独 Activity 调用测试代码。 MainActivityPayActivity渠道A包含不包含渠道B包含包含 因为支付功能需要引入对应的 moudule&#xff0c;因此…...

芝加哥学派(Chicago School):金融与经济学的创新力量(中英双语)

芝加哥学派&#xff1a;金融与经济学的创新力量 在经济学和金融学的历史上&#xff0c;有一个学派的影响力不容忽视&#xff0c;那就是芝加哥学派&#xff08;Chicago School&#xff09;。芝加哥学派不仅在学术界广受推崇&#xff0c;也深刻影响了全球的经济政策和金融市场。…...

3分钟了解内外网文件传输:常见方法、注意事项有哪些?

内外网文件传输不仅是企业日常运营的基础设施&#xff0c;更是支持业务增长、创新和合规的关键工具。通过高效、安全的文件传输&#xff0c;企业能够更好地应对全球化协作、远程办公和数据安全等挑战&#xff0c;从而在竞争激烈的市场中保持领先地位。 一、内外网文件传输的常…...

Python学习心得常用的内置函数

常用的内置函数&#xff1a; 1.数据类型转换函数&#xff1a; 描述说明 描述说明 bool(obj) 获取指定对象 obj 的布尔值 str(obj) 将指定对象 obj 转成字符串类型 int(x) 将 x 转成 int 类型 float(x) 将 x 转成 float 类型 list(sequence) 将序列转成列表类型 tu…...

VMware Workstation16安装Centos7以及静态IP设置

配置虚拟机操作系统 1.创建新的虚拟机 -> 自定义配置&#xff0c;下一步 2. 选择虚拟机硬件兼容性 -> 默认&#xff0c;下一步 3.安装客户机操作系统 -> 稍后安装操作系统&#xff0c;下一步 4.选择客户机操作系统 -> LinuxCentOS7 64 位&#xff0c;下一步 5.命名…...

【核心算法篇十九】《 DeepSeek因果推断:双重差分模型如何破解政策评估的「时空难题」》

一、当AB实验不可行时,我们该相信什么?(因果推断困局解析) 假设某城市推出「夜间地铁免费」政策,市长想知道这个政策是否真的提升了夜间经济。这时候你会发现: 1️⃣ 无法克隆城市:不能同时存在一个「实施政策」和「不实施政策」的平行宇宙 2️⃣ 数据混杂严重:疫情反…...

Token Embedding(词嵌入)和Positional Encoding(位置编码)的矩阵形状关系及转换过程

在从零开始构建一个小型字符级语言模型时,简化的实现步骤是:数据准备→模型架构设计→训练→评估与生成。模型架构设计阶段的流程如下: 图1 模型架构设计阶段的流程 包含了输入层、嵌入层、解码器层和输出层。其中在嵌入层中包括了Token Embedding(词嵌入)和Positional En…...

多个用户如何共用一根网线传输数据

前置知识 一、电信号 网线&#xff08;如以太网线&#xff09;中传输的信号主要是 电信号&#xff0c;它携带着数字信息。这些信号用于在计算机和其他网络设备之间传输数据。下面是一些关于网线传输信号的详细信息&#xff1a; 1. 电信号传输 在以太网中&#xff0c;数据是…...

U-Net 与深度学习的完美结合:图像分割的高效解决方案

1. 引言&#xff1a;U-Net背景及应用 1.1 U-Net的起源与发展 U-Net 是由 Olaf Ronneberger 和他的团队于2015年提出的卷积神经网络&#xff08;CNN&#xff09;架构。最初的设计目的是解决医学图像分割中的挑战&#xff0c;尤其是在有限的训练数据下如何实现准确的分割。 在…...

nginx ngx_http_module(9) 指令详解

nginx ngx_http_module(9) 指令详解 nginx 模块目录 nginx 全指令目录 一、目录 1.1 模块简介 ngx_http_uwsgi_module&#xff1a;uWSGI支持模块&#xff0c;允许Nginx与uWSGI服务器进行通信。uWSGI是一种应用服务器协议&#xff0c;广泛用于Python Web应用的部署。通过该…...

【从0做项目】Java搜索引擎(4)——性能优化~烧脑~~~

本篇文章将对项目搜索引擎&#xff08;1&#xff09;~&#xff08;3&#xff09;进行性能优化&#xff0c;包括测试&#xff0c;优化思路&#xff0c;优化前后对比 目录 一&#xff1a;文件读取 二&#xff1a;实现多线程制作索引 1&#xff1a;代码分析 2&#xff1a;代码…...

【HarmonyOS Next】鸿蒙应用进程和线程详解

【HarmonyOS Next】鸿蒙应用进程和线程详解 一、前言 进程的定义&#xff1a; 进程是系统进行资源分配的基本单位&#xff0c;是操作系统结构的基础。 在鸿蒙系统中&#xff0c;一个应用下会有三类进程&#xff1a; (1) 主进程&#xff0c; (2) ExtensionAbility进程&#xff…...

【前端ES】ECMAScript 2023 (ES14) 引入了多个新特性,简单介绍几个不为人知但却好用的方法

Array.prototype.toSorted() 返回一个新的已排序数组副本&#xff0c;不改变原数组。 let arr [5, 4, 2, 3, 1]; console.log(arr.toSorted()); // [1, 2, 3, 4, 5]Array.prototype.with() 允许根据索引修改数组中的单个元素&#xff0c;并返回新数组。 const arr ["…...

【EndNote】WPS 导入EndNote 21

写在前面&#xff1a;有没有人有激活码&#xff0c;跪求&#xff01; EndNote&#xff0c;在文献管理和文献引用方面很好用。写文章的时候&#xff0c;使用EndNote引入需要的文献会很方便。我目前用的WPS&#xff0c;想把EndNote的CWYW&#xff08;Cite While You Write&#…...

网上购物|基于SprinBoot+vue的网上购物系统(源码+数据库+文档)

网上购物系统目录 基于SprinBootvue的网上购物 一、前言 二、系统设计 三、系统功能设计 5.1 管理员功能实现 5.1.1 论坛管理 5.1.2 商品管理 5.1.3 商品评价管理 5.1.4 商品订单管理 5.2 用户功能实现 5.2.1 商品信息 5.2.2 确认下单 5.2.3 商品订单 5.2.4 购物…...

AI 语言模型发展史:统计方法、RNN 与 Transformer 的技术演进

引言 自然语言处理&#xff08;NLP&#xff09;是 AI 领域的重要分支&#xff0c;而语言模型&#xff08;Language Model, LM&#xff09;是 NLP 的核心技术。语言模型经历了从 统计方法 到 RNN&#xff08;循环神经网络&#xff09;&#xff0c;再到 Transformer 的演进&…...

Pycharm中查找与替换

1、Edit -> Find -> Find 在当前文件中查找 2、Edit -> Find -> Find in Files 在所有文件中查找 3、Edit -> Find -> Replace 在当前文件中执行替换 4、Edit -> Find -> Replace in Files 在所有文件中执行替换...

有向图的强连通分量: Kosaraju算法和Tarjan算法详解

在上一篇文章中, 我们了解了图的最小生成树算法. 本节我们来学习 图的强连通分量(Strongly Connected Component, SCC) 算法. 什么是强连通分量? 在 有向图 中, 若一组节点内的任意两个节点都能通过路径互相到达(例如 A → B A \rightarrow B A→B 且 B → A B \rightarro…...

mac相关命令

显示和隐藏usr等隐藏文件文件 terminal输入: defaults write com.apple.Finder AppleShowAllFiles YESdefaults write com.apple.Finder AppleShowAllFiles NO让.bashrc每次启动shell自动生效 编辑vim ~/.bash_profile 文件, 加上 if [ -f ~/.bashrc ]; then. ~/.bashrc fi注…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...