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

news2024/11/13 22:56:05

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

引言

适配器模式(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.coloradmin.cn/o/1928905.html

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

相关文章

AI论文精读笔记-MAE

1. 论文基本信息 论文标题:Masked Autoencoders Are Scalable Vision Learners 作者:Kaiming He∗,† Xinlei Chen∗ Saining Xie Yanghao Li Piotr Doll ́ ar Ross Girshick 发表时间和期刊:19 Dec 2021; arxiv 论文链接:Mas…

苹果预计因Apple Intelligence引发设备升级潮

🦉 AI新闻 🚀 苹果预计因Apple Intelligence引发设备升级潮 摘要:据彭博社报道,摩根士丹利将苹果列为首选股票,预期Apple Intelligence发布将引发创纪录的设备升级。分析师Erik Woodring 将苹果目标股价上调至273美元…

前端开发(基础)

目录 一、Web前端项目初始化 环境准备 创建项目 前端工程化配置 引入组件库 开发规范 全局通用布局 基础布局结构 全局底部栏 动态替换内容 全局顶部栏 通用路由菜单 支持多套布局 请求 请求工具库 全局自定义请求 自动生成请求代码 全局状态管理 全局权限管…

电力调度台如何助力电力指挥中心更智慧

在现代电力系统的复杂运行环境中,电力调度台正逐渐成为电力指挥中心实现智慧化管理的关键力量。 电力调度台具备强大的信息集成与处理能力。它能够将来自不同监测系统、传感器和数据源的海量数据汇聚一处,包括电力设备的实时运行状态、电力负荷的动态变化…

应急靶场(4):Windows Server 2019 - Web3

目录 一、攻击者的两个IP地址 二、隐藏用户名称 三、黑客遗留下的flag【3个】 下载好靶场(前来挑战!应急响应靶机训练-Web3)并搭建好环境,使用帐号密码(administrator / xj123456)登录靶机。 一、攻击者的两…

张幼玲:心中有火,眼里有光照医路

在我们的传统社会中,男科医生这一职业往往被人们带着异样的眼光看待。然而,张幼玲却选择了这一领域,成为了一名专业男科医生。他以其丰富的临床经验、高超的医术和对患者的关爱,赢得了患者和社会的广泛赞誉。 张幼玲出生于一个中医…

ASP.NET Core----基础学习06----将所有数据在页面中显示 布局页面的使用

文章目录 1. 将数据以list的形式展示在页面中2. 布局页面的使用3. 自定义设置视图文件是否需要加载的JS 1. 将数据以list的形式展示在页面中 step1:在接口文件中添加新的方法GetAllStudents() step2:在mock的数据中添加方法GetAllStudents(&a…

7/13 - 7/15

vo.setId(rs.getLong("id"))什么意思? vo.setId(rs.getLong("id")); 这行代码是在Java中使用ResultSet对象(通常用于从数据库中检索数据)获取一个名为"id"的列,并将其作为long类型设置为一个对象…

Billu_b0x靶机

信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令: arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令: nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…

工作中项目git如何管理,冲突,push不上去如何解决

主要涉及的知识点 现在公司中一般的git仓库的管理方式是怎么样的代码为什么push不上线上仓库如何解决代码冲突 分支管理方式 git checkout -b 分支名字 是创建并切换到分支 git push origin 分支名字 推到远程仓库分支上 主流的git管理方式 共用一个仓库,不同…

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

题目: 题解: func deleteNode(node *ListNode) {node.Val node.Next.Valnode.Next node.Next.Next }

解决宝塔Spring Boot项目获取不到环境变量的问题

问题描述 在使用宝塔面板管理Spring Boot项目时,可能会遇到代码无法获取 /etc/profile 文件中设置的Linux环境变量的问题。虽然在SSH终端中可以正常获取,但在通过宝塔面板启动的Spring Boot项目中,环境变量却无法被读取。 解决方案&#xf…

TS 入门(三):Typescript函数与对象类型

目录 前言回顾1. 函数类型a. 基本函数类型b. 可选参数和默认参数c. 剩余参数 2. 对象类型a. 基本对象类型b. 可选属性和只读属性 3. 类型别名和接口a. 类型别名b. 接口扩展 4. 类型推断和上下文类型a. 类型推断b. 上下文类型 扩展知识点:函数重载结语 前言 在前两章…

实验06 持续集成测试

知识点 集成测试定义 集成测试是将多个单元组合起来形成更大的单元,并测试它们是否能协同工作形成子系统。一种旨在暴露单元接口之间、组件/系统间交互或协同工作时所存在的缺陷的测试。 集成测试关注的问题 模块间数据传递是否正确。一个模块的功能是否影响另一…

[iOS]内存分区

[iOS]内存分区 文章目录 [iOS]内存分区五大分区栈区堆区全局区常量区代码区验证内存使用注意事项总结 函数栈堆栈溢出栈的作用 参考博客 在iOS中,内存主要分为栈区、堆区、全局区、常量区、代码区五大区域 还记得OC是C的超类 所以C的内存分区也是一样的 iOS系统中&a…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑频率不同响应阶段的惯量评估优化策略》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

嵌入式人工智能(6-树莓派4B按键输入控制LED)

1、按键 按键的原理都是一样,通过按键开关的按下导通,抬起断开的情况,GPIO引脚来检测其是否有电流流入。GPIO有input()方法,对于GPIO引脚检测电流,不能让其引脚悬空,否则引脚会受周边环境电磁干扰产生微弱…

《昇思25天学习打卡营第15天|计算机视觉-SSD目标检测》

FCN图像语义分割&ResNet50迁移学习&ResNet50图像分类&ShuffleNet图像分类&SSD目标检测 SSD目标检测 模型简介 SSD,全称Single Shot MultiBox Detector,是Wei Liu在ECCV 2016上提出的一种目标检测算法。使用Nvidia Titan X在VOC 2007测…

重塑水利未来:智慧水利解决方案的探索与实践,从物联网、大数据到人工智能,科技如何赋能水利行业,实现智慧化管理与决策

本文关键词:智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…

达梦数据库的系统视图v$systeminfo

达梦数据库的系统视图v$systeminfo 在达梦数据库(DM Database)中,V$SYSTEMINFO 是一个系统视图,用于显示数据库实例的系统信息。这个视图提供了关于数据库实例的运行状态、配置参数、资源使用情况等重要信息,对于数据…