Java二十三种设计模式-适配器模式(6/23)

适配器模式:使不兼容的接口协同工作的桥梁

引言

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间可以一起工作,通过将一个类的接口转换成客户端期望的另一个接口。

在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

基础知识,java设计模式总体来说设计模式分为三大类:

(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

第一部分:适配器模式概述

1.1 定义与目的

适配器模式的基本定义

适配器模式是一种结构型设计模式,其目的是通过一个中间层(适配器)将一个类的接口转换成客户端期望的另一个接口,从而使原本不兼容的接口能够一起工作。

解释为何需要适配器模式

  • 接口不兼容:当现有的类库提供的接口与消费者期望的接口不一致时,适配器模式提供了一种解决方案。
  • 重用现有类:适配器模式允许重用现有的类,即使这些类的接口不完全符合需求。
  • 解耦系统组件:适配器模式将接口转换逻辑与使用这些接口的客户端代码分离,降低了系统组件之间的耦合度。

1.2 适配器模式的类型

类适配器模式

  • 定义:通过继承和组合的方式,将一个类的接口转换成另一种形式。
  • 实现方式:创建一个新类(适配器类),继承目标接口,并在内部包含一个被适配者的实例。
  • 适用场景:当需要适配的类可以被继承,或者需要将多个不兼容的接口整合到一个统一的接口时。

对象适配器模式

  • 定义:通过对象组合的方式,让一个类的接口转换成客户期望的另一个接口。
  • 实现方式:创建一个新类(适配器类),实现目标接口,并通过引用包含一个被适配者的对象。
  • 适用场景:当需要适配的类不能被继承,或者想要避免使用继承时。

类适配器模式和对象适配器模式的对比

  • 继承与组合:类适配器模式使用继承实现,而对象适配器模式使用对象组合实现。
  • 灵活性:对象适配器模式提供了更高的灵活性,可以在运行时动态地更换适配器中的被适配者对象。
  • 复杂性:类适配器模式可能会增加系统的复杂性,因为它涉及到类的继承。

适配器模式通过提供一个中间层来转换接口,使得不兼容的接口能够协同工作。选择合适的适配器模式类型(类适配器或对象适配器)取决于是否需要继承被适配者以及对系统灵活性的需求。在下一部分中,我们将详细介绍适配器模式的组成与实现。

第二部分:适配器模式的组成与实现

2.1 角色定义

目标接口(Target Interface)

  • 定义:客户端所期望的接口。
  • 角色:定义客户端使用的特定领域相关的接口。

适配器类(Adapter Class)

  • 定义:适配器模式的核心,实现目标接口并包含对被适配者的引用。
  • 角色:通过在内部使用被适配者对象,把被适配者的接口转换成客户端期望的接口。

客户端(Client)

  • 角色:使用目标接口的类,不知道适配器内部如何工作的。
  • 职责:通过目标接口与适配器交互,达到与被适配者交互的目的。

被适配者(Adaptee)

  • 定义:一个已经存在的类,需要适配。
  • 角色:提供原始的操作和数据,但接口与客户端期望的接口不兼容。

2.2 Java实现示例

以下是使用Java语言实现适配器模式的示例。假设我们有一个不兼容的接口Adaptee,我们希望将其适配到客户端期望的Target接口。

// 目标接口
interface Target {
    void request();
}

// 被适配者接口
class Adaptee {
    public void specificRequest() {
        System.out.println("Executing specific request.");
    }
}

// 类适配器模式
class Adapter extends Adaptee implements Target {
    public void request() {
        specificRequest(); // 将被适配者的方法映射到目标接口
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Target adapter = new Adapter();
        adapter.request();
    }
}

在这个示例中,Adapter类继承自Adaptee并实现了Target接口。request()方法将AdapteespecificRequest()方法映射到Target接口上,从而使得客户端可以通过Target接口与Adaptee对象交互。

对象适配器实现示例

// 目标接口
interface Target {
    void request();
}

// 被适配者
class Adaptee {
    public void specificRequest() {
        System.out.println("Executing specific request.");
    }
}

// 对象适配器模式
class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void request() {
        adaptee.specificRequest(); // 委托给被适配者
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target adapter = new ObjectAdapter(adaptee);
        adapter.request();
    }
}

在这个对象适配器示例中,ObjectAdapter类实现了Target接口,并通过组合Adaptee对象来实现request()方法。这种方式提供了更大的灵活性,允许在运行时动态地更换被适配者对象。

适配器模式通过将一个类的接口转换成另一种形式,使得原本由于接口不兼容而不能一起工作的类可以协同工作。在下一部分中,我们将探讨适配器模式的使用场景。

第三部分:适配器模式的使用场景

3.1 系统间的接口不兼容

在软件开发过程中,经常会遇到需要集成不同系统的情况,这些系统可能因为设计时间、设计团队或者技术选型的差异而拥有不同的接口规范。

适配器模式如何发挥作用:

  • 统一接口:适配器模式通过提供一个统一的接口,使得不同系统的组件能够以一致的方式进行交互。
  • 减少修改:避免了对现有系统接口的修改,保护了现有系统的稳定性。
  • 简化集成:简化了不同系统间集成的复杂性,因为所有的交互都通过适配器进行。

应用实例:

  • 支付系统集成:在电子商务平台中,可能需要集成多种支付方式,如支付宝、微信支付等。每种支付方式都有自己特定的接口,通过适配器模式可以为平台提供一个统一的支付接口。

3.2 重用现有的类库

在许多情况下,开发者需要重用现有的类库,但这些类库的接口可能与当前系统的接口不兼容。

适配器模式的优势:

  • 提高复用性:适配器模式使得开发者能够重用现有的类库,即使这些类库的接口不完全符合当前系统的需求。
  • 解耦系统:适配器模式将接口转换逻辑与系统其他部分解耦,提高了系统的灵活性和可维护性。
  • 降低成本:通过适配器模式重用现有的类库,可以减少开发时间和成本。

应用实例:

  • 第三方API集成:在开发移动应用时,可能需要集成第三方API,如地图服务、社交媒体分享等。这些API可能具有不同的接口风格,适配器模式可以为应用提供一个统一的接口来访问这些服务。

适配器模式通过提供一个中间层来转换接口,使得不兼容的接口能够协同工作。它在系统间的接口不兼容和需要重用现有类库的场景下尤其有用。在下一部分中,我们将讨论适配器模式的优点与缺点。

第四部分:适配器模式的优点与缺点

4.1 优点

提高兼容性

  • 接口统一:适配器模式允许通过统一的接口与多种不同的接口进行交互,提高了不同系统或组件之间的兼容性。

复用性增强

  • 现有类库利用:适配器模式使得开发者能够复用现有的类库,即使这些库的接口与需求不完全匹配。
  • 减少代码冗余:通过适配器模式,避免了对不兼容接口的多次修改和适配,减少了代码冗余。

灵活性提升

  • 动态替换:在对象适配器模式中,可以在运行时动态地替换适配器中的被适配者对象,提高了系统的灵活性。

降低耦合度

  • 解耦系统组件:适配器模式将客户端与被适配者解耦,减少了它们之间的依赖关系。

4.2 缺点

增加系统的复杂性

  • 类或对象数量增加:适配器模式可能会增加系统中类或对象的数量,从而增加了系统的复杂性。

降低代码的透明度

  • 隐藏实现细节:适配器模式可能会隐藏被适配者的一些实现细节,使得客户端难以理解适配器的具体行为。

适配器职责过重

  • 适配器类膨胀:如果适配器承担了过多的适配职责,可能会导致适配器类过于庞大和复杂。

难以维护

  • 多个适配器维护:在系统中使用多个适配器时,可能难以维护和更新这些适配器。

性能考虑

  • 性能开销:适配器模式可能会引入额外的性能开销,尤其是在适配器执行复杂转换逻辑时。

适配器模式是一种强大的设计模式,可以提高系统的兼容性和复用性,同时提供灵活性和降低耦合度。然而,它也需要谨慎使用,以避免增加系统的复杂性和维护难度。在实际应用中,根据具体需求和场景选择是否使用适配器模式至关重要。在下一部分中,我们将比较适配器模式与其他设计模式,并提供一些最佳实践和建议。

第五部分:适配器模式与其他模式的比较

5.1 与装饰者模式的比较

装饰者模式

  • 定义:允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰者提供了一种灵活的替代方案来扩展功能。
  • 使用场景:当你需要为对象动态地添加职责,但又不想用继承来实现时。

适配器模式

  • 定义:将一个类的接口转换成客户期望的另一个接口,使原本由于接口不兼容而不能一起工作的类可以协同工作。
  • 使用场景:当需要整合使用不同接口的类库时。

对比

  • 目的不同:装饰者模式的目的是增加对象的额外职责,而适配器模式的目的是使接口不兼容的对象能够一起工作。
  • 结构变化:装饰者模式通过组合可以动态地添加新的行为,而适配器模式通常在编译时就已经确定。
  • 使用方式:装饰者模式可以多层嵌套使用,形成装饰者链,而适配器模式通常只用于单个接口的转换。

5.2 与外观模式的对比

外观模式

  • 定义:提供了一个统一的接口,用来访问子系统中的一群接口,它定义了一个高层接口,让子系统更容易使用。
  • 使用场景:当需要简化复杂的系统或库的接口,提供简化的访问方式时。

适配器模式

  • 定义:允许不兼容的接口一起工作,通过创建一个中间层来转换接口。

对比

  • 接口简化:外观模式用于简化复杂系统的接口,而适配器模式用于解决接口不兼容的问题。
  • 目标不同:外观模式的目标是提供一个更简单的接口,隐藏内部的复杂性;适配器模式的目标是使得不同接口能够协同工作。
  • 使用范围:外观模式通常用于整个系统的简化,而适配器模式可以用于单个接口的转换或整个子系统的适配。

适配器模式、装饰者模式和外观模式都是常用的结构型设计模式,它们各自解决不同的设计问题。适配器模式专注于接口的兼容性,装饰者模式用于动态地添加职责,而外观模式用于简化复杂系统的接口。在实际应用中,根据具体的需求和场景选择合适的模式是非常重要的。在下一部分中,我们将提供适配器模式的最佳实践和建议。

第六部分:适配器模式的最佳实践和建议

6.1 最佳实践

保持适配器的简洁性

  • 单一职责:确保适配器只处理与接口转换相关的逻辑,避免添加额外的业务逻辑。

明确适配器的角色

  • 作为中介:适配器应该仅仅作为一个中介,不参与业务逻辑的实现。

适配器的扩展性

  • 预留扩展点:在设计适配器时,考虑未来可能的扩展,使适配器能够容易地适应新的接口变化。

适配器与被适配者的关系

  • 松耦合:适配器与被适配者之间应保持松耦合的关系,减少对被适配者内部实现的依赖。

适配器的测试

  • 独立测试:为适配器编写单元测试,确保其正确地转换接口。

6.2 避免滥用

避免过度耦合

  • 减少依赖:避免适配器对被适配者的过度依赖,这样当被适配者变化时,适配器不会受到太大影响。

避免适配器过于复杂

  • 单一功能:确保适配器专注于单一功能的适配,避免将多个适配逻辑混合在一个适配器中。

避免适配器的过度使用

  • 合理使用:适配器模式应该在确实需要接口转换时使用,而不是作为一种习惯性的设计手段。

6.3 替代方案

使用桥接模式

  • 定义:桥接模式将抽象部分与其实现部分分离,使它们可以独立地变化。
  • 适用场景:当需要将一个类族的功能和实现分离,以便独立地进行扩展时。

使用组合模式

  • 定义:组合模式允许将对象组合成树形结构以表示“部分-整体”的层次结构。
  • 适用场景:当需要处理的对象可以形成树形结构时。

使用继承

  • 适用场景:如果适配器模式用于解决继承问题,可以考虑使用继承来实现功能扩展。

使用外观模式

  • 适用场景:当需要简化复杂系统的接口时,可以考虑使用外观模式。

适配器模式是一种强大的设计模式,可以提高系统的兼容性和复用性。然而,合理使用适配器模式并避免滥用是至关重要的。了解其替代方案可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用适配器模式,以达到最佳的设计效果。

 

结语

适配器模式是一种在软件开发中常用的设计模式,它帮助解决了接口不兼容的问题,提高了代码的复用性。通过本文的深入分析,希望读者能够对适配器模式有更全面的理解,并在实际开发中做出合理的设计选择。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第237题删除链表中的节点

题目: 题解: class Solution {public void deleteNode(ListNode node) {node.val node.next.val;node.next node.next.next;} }

Windows上LabVIEW编译生成可执行程序

LabVIEW项目浏览器(Project Explorer)中的"Build Specifications"就是用来配置项目发布方法的。在"Build Specifications"右键菜单中选取"New",可以看到程序有几种不同的发布方法:Application(EXE)、Installer、.Net Inte…

Redis的热key解决

1、Redis热Key会带来哪些问题 1、流量集中,达到物理网卡上限。 当某一热点 Key 的请求在某一主机上超过该主机网卡上限时,由于流量的过度集中,会导致服务器中其它服务无法进行。 2、请求过多,缓存分片服务被打垮。 如果热点过于…

深入理解缓冲区:提升程序性能的关键

深入理解缓冲区:提升程序性能的关键 1、什么是缓冲区?2、缓冲区的作用3、缓冲区在Java中的应用4、如何操作缓冲区5、总结 💖The Begin💖点点关注,收藏不迷路💖 缓冲区(Buffer)是一种…

mac电脑pdf合并,macpdf合并成一个pdf

在数字化办公和学习的今天,pdf文件因其跨平台兼容性强、格式稳定而成为了最受欢迎的文档格式之一。但随之而来的问题也接踵而至,如何将多个pdf文件合并为一个?这不仅关系到文档的整洁性,更是时间管理的重要环节。今天,…

安全防御:防火墙基本模块

目录 一、接口 1.1 物理接口 1.2 虚拟接口 二、区域 三、模式 3.1 路由模式 3.2 透明模式 3.3 旁路检测模式 3.4 混合模式 四、安全策略 五、防火墙的状态检测和会话表技术 一、接口 1.1 物理接口 三层口 --- 可以配置IP地址的接口 二层口: 普通二层…

CSS在页面中使用的三种方式:行内样式、内嵌式样式表、链接式样式表

CSS样式如何在页面中使用,包含三种方式:行内样式、内嵌式样式表、链接式样式表。 CSS样式的使用系列博文: 《CSS在页面中使用的三种方式:行内样式、内嵌式样式表、链接式样式表》 《CSS选择器:基本选择器、复合选择器、…

[Vulnhub] violator ProFTPD+权限提升

信息收集 IP addressOpening Ports192.168.101.148TCP:21,80,2121 $ nmap -p- 192.168.101.148 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD 1.3.5rc3 80/tcp open http Apache httpd 2.4.7 ((Ubuntu)) |_http-title: I Say...…

isaac sim中添加fix joint时,坐标系固定不动问题

例如想为机械臂末端增加一个工具坐标系,此时在flange中添加fixjoint,并依次添加flage和xform 如何xfrom没有添加rigid body属性的话,那么xfrom坐标系就会固定在世界坐标系中,程序启动后机械臂会移动到该坐标系处,并且无…

SpringBoot实现图形验证码

目录 项目创建 前端代码实现 约定前后端交互接口 需求分析 接口定义 Hutool工具 实现服务器端代码 引入依赖 获取验证码 验证码校验 调整前端代码 随着安全性的要求越来越高,目前许多项目中都使用了验证码,验证码也有各种类型,如 …

JavaWeb(四:Ajax与Json)

一、Ajax 1.定义 Ajax(Asynchronous JavaScript And XML):异步的 JavaScript 和 XML AJAX 不是新的编程语言,指的是⼀种交互方式:异步加载。 客户端和服务器的数据交互更新在局部页面的技术,不需要刷新…

android13 frameworks里面常用的保存信息或者版本判断的方法

总纲 android13 rom 开发总纲说明 目录 1.前言 2. 数据库 2.1 代码读取用法参考 3.prop 属性配置 3.1 property的key值有哪些特点 4.区别 5. 其他数据存储 6.彩蛋 1.前言 frameworks 不像我们一般开发app那样,很多应用保存的方法都无法使用。这里记录我们系统rom开…

【首发】分享一款三网话费余额查询的API系统

描述 对于计算机专业的小伙伴来说,多熟悉一个系统就多一份就业机会! 今天给大家分享一款三网话费余额查询的API系统 亲测可运行!! 内容 目前主要的内容以php为主,对于学习php有比较大的帮助! 但是网络上…

信息系统项目管理师(高项)—学习笔记二

第一章 以下是上一篇(信息系统项目管理师(高项)—学习笔记)的续写,因为是之前记录的,这一篇还是细致到每一个小节的内容,有些过于复杂了,后续会简化~ 1.3 现代化创新发展 党的十九…

亚信安全发布2024年第24期《勒索家族和勒索事件监控报告》

本周态势快速感知 本周,勒索软件LockBit涉嫌对美国一家生产乙烯基产品的公司(Homeland Vinyl)进行攻击。LockBit声称他们已窃取了销售、库存、财务交易数据及其他公司记录,并声明将于2024年7月19日公开这些被盗信息。本周全球共监…

基于双向长短期记忆 BiLSTM 实现股票单变量时间序列预测(PyTorch版)

前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…

GitHub连接超时问题 Recv failure: Connection was reset

用手机热点WIF拉取git项目的时候,遇到Recv failure: Connection was reset问题。 解决办法 一、手动开启本地代理 二、在终端(cmd)输入命令 git config --global http.proxy http://127.0.0.1:7890 git config --global https.proxy https:…

使用Nginx OpenResty与Redis实现高效IP黑白名单管理

1、引言 在当今数字化时代,网络安全已成为企业和个人用户关注的焦点。IP黑白名单作为一种有效的网络安全策略,允许我们精确控制对Web资源的访问权限。通过白名单,我们可以确保只有可信的IP地址能够访问敏感资源;而黑名单则可以阻…

Springboot交流论坛网站-计算机毕业设计源码00304

摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了交流论坛网站的开发全过程。通过分析交流论坛网站管理的不足,创建了一个计算机管理交流论坛网站的方案。文章介绍了交流论坛网站的系统分析部分&…

手机和电脑通过TCP传输(一)

一.工具 手机端:网络调试精灵 电脑端:野火网络调试助手 在开始通信之前,千万要查看一下电脑的防火墙是否关闭,否则可能会无法通信 在开始通信之前,千万要查看一下电脑的防火墙是否关闭,否则可能会无法通信…