一文搞懂设计模式—适配器模式

本文已收录至Github,推荐阅读 👉 Java随想录

微信公众号:Java随想录

文章目录

    • 使用场景
    • 实现方式
      • 类适配器实现
      • 对象适配器实现
    • 优缺点
    • 总结

适配器模式(Adapter Pattern)属于结构型模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的类之间进行合作,使得原本因接口不匹配而无法工作的类能够协同工作。

使用场景

适配器模式在以下情况下特别有用:

  • 当你想使用一个已经存在的类,但其接口与你的需求不匹配时。
  • 当你想创建一个可复用的类,该类与其他不相关的类或不可预见的类进行交互。
  • 当我们有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

实现方式

适配器模式的实现通常涉及三个角色:目标接口、适配器和被适配者。

  • 目标接口:定义了客户端需要使用的方法,是客户端期望的接口。
  • 适配器:实现了目标接口,并包含一个对被适配者的引用。通过对被适配者的调用来完成客户端请求。
  • 被适配者:已经存在的类或接口,与目标接口不兼容。

在 Java 中,一个常见的使用适配器模式的例子是InputStreamReader类。该类是Java I/O库中用于将字节流(InputStream)适配成字符流(Reader)的适配器。

FileInputStream fis = new FileInputStream("hello world");
InputStreamReader adapter = new InputStreamReader(fis);
BufferedReader bfr = new BufferedReader(adapter);

在这个示例中,客户需要使用BufferedReader来读取文件字符流。然而,现有的接口只能提供字节流,例如FileInputStream。为了满足客户的需求,我们需要对现有的接口进行适配。

InputStreamReader充当了适配器的角色。它持有一个FileInputStream对象,并通过适配将其转换为所需的字符流接口。可以将InputStreamReader视为适配器模式的具体实现之一。

通过使用适配器模式,我们成功地将字节流接口适配成了字符流接口,使得BufferedReader能够以字符方式读取文件内容,从而满足了客户的需求。

适配器模式有两种比较常见的实现方式:

  • 类适配器模式(使用继承)
  • 对象适配器模式(使用组合)

类适配器实现

类适配器通过继承来实现适配器功能

// 目标接口
public interface Target {void request();
}// 被适配者
public class Adaptee {public void specificRequest() {System.out.println("Adaptee: specificRequest");}
}// 适配器
public class Adapter extends Adaptee implements Target {/*** 采用继承的方式实现转换功能*/@Overridepublic void request() {super.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request(); // 通过适配器调用被适配者方法}
}

对象适配器实现

对象适配器通过组合来实现适配器功能

以下是一个简单的示例代码:

// 目标接口
public interface Target {void request();
}// 被适配者
public class Adaptee {public void specificRequest() {System.out.println("Adaptee: specificRequest");}
}// 适配器
public class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request(); // 通过适配器调用被适配者方法}
}

对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。

一般而言,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,可以适配不同的被适配类,并且允许动态替换被适配对象。另外,对象适配器不受被适配类的限制。

类适配器通过继承现有接口类并实现目标接口,这样的话会使得现有接口类完全对适配器暴露,使得适配器具有现有接口类的全部功能,破坏了封装性,会引入一些设计上的限制。此外从逻辑上来说,这也是不符合常理的,适配器要做的是扩展现有接口类的功能而不是替代,类适配器只有在特定条件下会被使用。

对象适配器持有现有接口类一个实例,并扩展其功能,实现目标接口。这是推荐的方式,优先采用组合而不是继承,会使得代码更利于维护。

优缺点

优点:

  • 透明性:适配器模式可以使客户端对目标类和适配者类的使用变得透明。客户端只需要与目标接口进行交互,无需了解适配者类的内部实现细节。
  • 重用性:通过适配器模式,可以复用已经存在的可复用类。适配器将这些类适配到目标接口中,使得它们可以在新的环境下被重用。
  • 灵活性:适配器模式可以动态地适配不同的适配者类,从而满足不同的客户端需求。适配器模式允许在运行时更改适配器,以适应不同的情况和要求。

缺点:

  • 过多的适配器类:如果系统中存在大量的适配器类,会让系统非常零乱,不易整体进行把握,可能会导致代码结构的复杂性增加。
  • 可能引入额外的复杂性:适配器模式可能会导致系统中增加额外的类和对象,从而增加系统的复杂性。

总结

适配器模式通过将不兼容的接口转换为可协同工作的形式,实现了不同类之间的互操作。它可以提高代码的复用性和灵活性。但在使用过程中需要注意选择合适的适配器类型,并确保适配器能够正确地转换接口。

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

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

相关文章

《剑指 Offer》专项突破版 - 面试题 45 和 46 : 二叉树最低层最左边的值和二叉树的右侧视图(C++ 实现)

目录 面试题 45 : 二叉树最低层最左边的值 面试题 46 : 二叉树的右侧视图 面试题 45 : 二叉树最低层最左边的值 题目: 如何在一棵二叉树中找出它最低层最左边节点的值?假设二叉树中最少有一个节点。例如,在下图所示的二叉树中最低层最左边…

Codeforces Round 924 (Div. 2)题解(A-D)

A - Rectangle Cutting 链接&#xff1a;A - Rectangle Cutting 思路 考虑横边和纵边&#xff0c;若为偶数&#xff0c;则从中间分开&#xff0c;重新组合为一个长方形&#xff0c;检测是否与原来的长方形一致。 代码 #include <bits/stdc.h> using namespace std;i…

logback实践

1:日志区分环境 2:debug info warn error日志文件不一样 3: 文件滚动日志 4:启动可带参数 --spring.profiles.activedev --log.levelinfo 5:可从配置文件中获取上下文参数 logback-spring.xml 放在 classpath 下面 <configuration scan"false" scanPer…

探秘OpenAI的神奇之作:Sora技术揭秘

探秘OpenAI的神奇之作&#xff1a;Sora技术揭秘 1. 引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;正日益成为各个领域的关键技术。而在人工智能领域中&#xff0c;OpenAI公司一直以来都扮演着重要的角色。他们的最新创新——Sora技术&#x…

基于python的遥感影像灰色关联矩阵纹理特征计算

遥感影像纹理特征是描述影像中像素间空间关系的统计特征&#xff0c;常用于地物分类、目标识别和变化检测等遥感应用中。常见的纹理特征计算方式包括灰度共生矩阵&#xff08;GLCM&#xff09;、灰度差异矩阵&#xff08;GLDM&#xff09;、灰度不均匀性矩阵&#xff08;GLRLM&…

常见面试题:TCP的四次挥手和TCP的滑动窗口

说一说 TCP 的四次挥手。 挥手即终止 TCP 连接&#xff0c;所谓的四次挥手就是指断开一个 TCP 连接时。需要客户端和服务端总共发出四个包&#xff0c;已确认连接的断开在 socket 编程中&#xff0c;这一过程由客户端或服务端任意一方执行 close 来触发。这里我们假设由客户端…

unity学习(29)——GameInfo角色信息

1.把GameInfo.cs PlayerModel.cs Vector3.cs Vector4.cs PlayerStateConstans.cs GameState.cs依次粘到model文件夹中&#xff0c;此时项目没有错误&#xff0c;如下图所示&#xff1b; 对应处所修改的代码如下&#xff1a; case LoginProtocol.LOGIN_SRES://1 {Debug.Log(&qu…

考研查分,别再只知道研招网了!

查分时间基本已经敲定在2月26日左右了。倒计时7天&#xff01;每年查询分数的时候经常因为查询人数太多&#xff0c;进不去研招网&#xff0c;还有哪些方法可以查询分数呢&#xff1f; 我为大家整理了四种常用的查成绩方式&#xff0c;附带部分已公布查分时间院校名单。 一、…

Java学习心得感悟

在我踏入Java学习的道路之前&#xff0c;我对编程只是一知半解&#xff0c;对于代码的世界充满了好奇和向往。然而&#xff0c;当我真正开始学习Java时&#xff0c;我才意识到&#xff0c;学习Java不仅仅是学习一门编程语言&#xff0c;更是一种思维方式和解决问题的能力的培养…

【AI视野·今日Sound 声学论文速览 第四十九期】Wed, 17 Jan 2024

AI视野今日CS.Sound 声学论文速览 Wed, 17 Jan 2024 Totally 23 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers From Coarse to Fine: Efficient Training for Audio Spectrogram Transformers Authors Jiu Feng, Mehmet Hamza Erol, Joon Son Chung,…

Pandas Series Mastery: 从基础到高级应用的完整指南【第83篇—Series Mastery】

Pandas Series Mastery: 从基础到高级应用的完整指南 Pandas是Python中一流的数据处理库&#xff0c;它为数据科学家和分析师提供了强大的工具&#xff0c;简化了数据清理、分析和可视化的流程。在Pandas中&#xff0c;Series对象是最基本的数据结构之一&#xff0c;它为我们处…

Spring Security基础学习

一、SpringSecurity框架简介 二、SpringSecurity入门案例 三、SpringSecurity Web权限方案 四、SpringSecurity微服务权限方案 五、SpringSecurity原理总结

Unity中的Lerp插值的使用

Unity中的Lerp插值使用 前言Lerp是什么如何使用Lerp 前言 平时在做项目中插值的使用避免不了&#xff0c;之前一直在插值中使用存在误区&#xff0c;在这里浅浅记录一下。之前看的博客或者教程还多都存在一个“永远到达不了&#xff0c;只能无限接近”的一个概念。可能是之前脑…

open3d DBSCAN 聚类

DBSCAN 聚类 一、算法原理1.密度聚类2、主要函数 二、代码三、结果四、相关数据 一、算法原理 1.密度聚类 介绍 基于密度的噪声应用空间聚类(DBSCAN)&#xff1a;是一种无监督的ML聚类算法。无监督的意思是它不使用预先标记的目标来聚类数据点。聚类是指试图将相似的数据点分…

微信美容预约小程序开发实战教程,快速掌握开发技巧

如果你想开发一个美容美发小程序&#xff0c;以下是一个搭建指南&#xff0c;供你参考。 1. 使用第三方制作平台 首先&#xff0c;你需要使用一个第三方制作平台&#xff0c;如乔拓云网。在该平台上&#xff0c;你需要注册并登录&#xff0c;然后点击【轻应用小程序】进入设计…

springboot201基于SpringBoot的论坛系统设计与实现

论坛系统设计与实现 摘 要 如今的时代&#xff0c;是有史以来最好的时代&#xff0c;随着计算机的发展到现在的移动终端的发展&#xff0c;国内目前信息技术已经在世界上遥遥领先&#xff0c;让人们感觉到处于信息大爆炸的社会。信息时代的信息处理肯定不能用之前的手工处理这…

LineageOS:Android开源手机操作系统的未来之路

LineageOS&#xff1a;开源手机操作系统的未来之路 1. 引言 当前移动技术的迅猛发展使得手机操作系统变得至关重要。在众多操作系统中&#xff0c;LineageOS作为一款备受推崇的开源手机操作系统&#xff0c;其在过去几年中取得了显著的发展。本文将介绍LineageOS作为一款开源…

2009-2023年上市公司华证ESG评级得分数据

2009-2023年上市公司华证ESG评级得分数据 1、时间&#xff1a;2009-2023年 2、来源&#xff1a;华证ESG评级 3、范围&#xff1a;A股上市公司 4、指标&#xff1a;股票代码、证券简称、年份、ESG得分-年均值、ESG得分-年中位数 5、方法说明&#xff1a;将华证ESG评级进行赋…

力扣题目训练(16)

2024年2月9日力扣题目训练 2024年2月9日力扣题目训练530. 二叉搜索树的最小绝对差541. 反转字符串 II543. 二叉树的直径238. 除自身以外数组的乘积240. 搜索二维矩阵 II124. 二叉树中的最大路径和 2024年2月9日力扣题目训练 2024年2月9日第十六天编程训练&#xff0c;今天主要…

Javascript中的let和var的详细区别

文章目录 前言var变量提升 let暂时性死区 具体的区别声明后未赋值&#xff0c;表现相同使用未声明的变量&#xff0c;表现不同重复声明同一个变量时&#xff0c;表现不同变量作用范围&#xff0c;表现不同 在JavaScript中我们每时每刻都在声明变量、使用变量&#xff0c;在之前…