23种设计模式漫画版系列—适配器模式(一)

简介: 23种设计模式漫画版系列—适配器模式

意图

适配器模式是一种结构型设计模式 它能使接口不兼容的对象能够相互合作


02问题

假如你正在开发一款股票市场监测程序 它会从不同来源下载 XML 格式的股票数据 然后向用户呈现出美观的图表

在开发过程中 你决定在程序中整合一个第三方智能分析函数库 但是遇到了一个问题 那就是分析函数库只兼容 JSON 格式的数据

你无法 直接 使用分析函数库 因为它所需的输入数据格式与你的程序不兼容

可以修改程序库来支持 XML 但是 这可能需要修改部分依赖该程序库的现有代码 甚至还有更糟糕的情况 你可能根本没有程序库的源代码 从而无法对其进行修改

03解决方案

你可以创建一个 这是一个特殊的对象 能够转换对象接口 使其能与其他对象进行交互

适配器模式通过封装对象将复杂的转换过程隐藏于幕后 被封装的对象甚至察觉不到适配器的存在 例如 你可以使用一个将所有数据转换为英制单位 如英尺和英里 的适配器封装运行于米和千米单位制中的对象

适配器不仅可以转换不同格式的数据 其还有助于采用不同接口的对象之间的合作 它的运作方式如下

1. 适配器实现与其中一个现有对象兼容的接口

2. 现有对象可以使用该接口安全地调用适配器方法

3. 适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象

有时你甚至可以创建一个双向适配器来实现双向转换调用


让我们回到股票市场程序 为了解决数据格式不兼容的问题 你可以为分析函数库中的每个类创建将 XML 转换为 JSON 格式的适配器 然后让客户端仅通过这些适配器来与函数库进行交流 当某个适配器被调用时 它会将传入的 XML 数据转换为 JSON 结构 并将其传递给被封装分析对象的相应方法


04真实世界类比

出国旅行前后的旅行箱

果你是第一次从美国到欧洲旅行 那么在给笔记本充电时可能会大吃一惊 不同国家的电源插头和插座标准不同 美国插头和德国插座不匹配 同时提供美国标准插座和欧洲标准插头的电源适配器可以解决你的难题

05适配器模式结构

对象适配器

实现时使用了构成原则 适配器实现了其中一个对象的接口 并对另一个对象进行封装 所有流行的编程语言都可以实现适配器

类适配器

这一实现使用了继承机制 适配器同时继承两个对象的接口 请注意 这种方式仅能在支持多重继承的编程语言中实现 例如 C++

06伪代码

下列适配器模式演示基于经典的 方钉和圆孔 问题

让方钉适配圆孔

适配器假扮成一个圆钉 Round­Peg 其半径等于方钉 Square­Peg 横截面对角线的一半 即能够容纳方钉的最小外接圆的半径

// 假设你有两个接口相互兼容的类:圆孔(Round­Hole)和圆钉(Round­Peg)。class RoundHole is
    constructor RoundHole(radius) { ... }
    method getRadius() is
        // 返回孔的半径。
    method fits(peg: RoundPeg) is
        return this.getRadius() >= peg.getRadius()class RoundPeg is
    constructor RoundPeg(radius) { ... }
    method getRadius() is
        // 返回钉子的半径。// 但还有一个不兼容的类:方钉(Square­Peg)。class SquarePeg is
    constructor SquarePeg(width) { ... }
    method getWidth() is
        // 返回方钉的宽度。// 适配器类让你能够将方钉放入圆孔中。它会对 RoundPeg 类进行扩展,以接收适// 配器对象作为圆钉。class SquarePegAdapter extends RoundPeg is
    // 在实际情况中,适配器中会包含一个 SquarePeg 类的实例。
    private field peg: SquarePeg
    constructor SquarePegAdapter(peg: SquarePeg) is
        this.peg = peg
    method getRadius() is
        // 适配器会假扮为一个圆钉,
        // 其半径刚好能与适配器实际封装的方钉搭配起来。
        return peg.getWidth() * Math.sqrt(2) / 2// 客户端代码中的某个位置。hole = new RoundHole(5)rpeg = new RoundPeg(5)hole.fits(rpeg) // truesmall_sqpeg = new SquarePeg(5)large_sqpeg = new SquarePeg(10)hole.fits(small_sqpeg) // 此处无法编译(类型不一致)。small_sqpeg_adapter = new SquarePegAdapter(small_sqpeg)large_sqpeg_adapter = new SquarePegAdapter(large_sqpeg)hole.fits(small_sqpeg_adapter) // truehole.fits(large_sqpeg_adapter) // false



07适配器模式适合应用场景

当你希望使用某个类 但是其接口与其他代码不兼容时 可以使用适配器类

适配器模式允许你创建一个中间层类 其可作为代码与遗留类 第三方类或提供怪异接口的类之间的转换器

如果您需要复用这样一些类 他们处于同一个继承体系 并且他们又有了额外的一些共同的方法 但是这些共同的方法不是所有在这一继承体系中的子类所具有的共性

你可以扩展每个子类 将缺少的功能添加到新的子类中 但是 你必须在所有新子类中重复添加这些代码 这样会使得代码有坏味道

将缺失功能添加到一个适配器类中是一种优雅得多的解决方案 然后你可以将缺少功能的对象封装在适配器中 从而动态地获取所需功能 如要这一点正常运作 目标类必须要有通用接口 适配器的成员变量应当遵循该通用接口 这种方式同装饰模式非常相似


08实现方式

    1. 确保至少有两个类的接口不兼容

  • 一个无法修改 通常是第三方 遗留系统或者存在众多已有依赖的类 的功能性
  • 一个或多个将受益于使用服务类的
    2. 声明客户端接口 描述客户端如何与服务交互
    3. 创建遵循客户端接口的适配器类 所有方法暂时都为空
    4. 在适配器类中添加一个成员变量用于保存对于服务对象的引用 通常情况下会通过构造函数对该成员变量进行初始化 但有时在调用其方法时将该变量传递给适配器会更方便
    5. 依次实现适配器类客户端接口的所有方法 适配器会将实际工作委派给服务对象 自身只负责接口或数据格式的转换
    6. 客户端必须通过客户端接口使用适配器 这样一来 你就可以在不影响客户端代码的情况下修改或扩展适配器

09适配器模式优缺点

  • 你可以将接口或数据转换代码从程序主要业务逻辑中分离
  • 只要客户端代码通过客户端接口与适配器进行交互 你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器
  • 代码整体复杂度增加 因为你需要新增一系列接口和类 有时直接更改服务类使其与其他代码兼容会更简单

10与其他模式的关系

  • 桥接模式通常会于开发前期进行设计 使你能够将程序的各个部分独立开来以便开发 另一方面 适配器模式通常在已有程序中使用 让相互不兼容的类能很好地合作
  • 适配器可以对已有对象的接口进行修改 装饰模式则能在不改变对象接口的前提下强化对象功能 此外还支持递归组合则无法实现
  • 适配器能为被封装对象提供不同的接口 代理模式能为对象提供相同的接口 装饰则能为对象提供加强的接口
  • 外观模式为现有对象定义了一个新接口 适配器则会试图运用已有的接口通常只封装一个对象通常会作用于整个对象子系统上
  • 桥接 状态模式和策略模式在某种程度上包括适配器 模式的接口非常相似 实际上 它们都基于组合模式——即将工作委派给其他对象 不过也各自解决了不同的问题 模式并不只是以特定方式组织代码的配方 你还可以使用它们来和其他开发者讨论模式所解决的问题




相关文章
|
6月前
|
设计模式 Java API
重构旧代码的秘诀:用设计模式 - 适配器模式(Adapter)给Java项目带来新生
【4月更文挑战第7天】适配器模式是解决接口不兼容问题的结构型设计模式,通过引入适配器类实现目标接口并持有不兼容类引用,实现旧代码与新接口的协作。适用于处理兼容性问题、整合遗留代码和集成第三方库。应用时,识别不兼容接口,创建适配器类转换方法调用,然后替换原有引用。注意保持适配器简单、使用组合和考虑扩展性。过度使用可能导致系统复杂和维护成本增加,应谨慎使用。
101 4
|
6月前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
103 4
|
2月前
|
设计模式 Java 程序员
Java设计模式-适配器模式(8)
Java设计模式-适配器模式(8)
|
1月前
|
设计模式 Java
Java设计模式之适配器模式
这篇文章详细讲解了Java设计模式中的适配器模式,包括其应用场景、实现方式及代码示例。
42 0
|
6月前
|
设计模式 Java
【设计模式】JAVA Design Patterns——Adapter(适配器模式)
【设计模式】JAVA Design Patterns——Adapter(适配器模式)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
3月前
|
设计模式 XML 存储
【六】设计模式~~~结构型模式~~~适配器模式(Java)
文章详细介绍了适配器模式(Adapter Pattern),这是一种结构型设计模式,用于将一个类的接口转换成客户期望的另一个接口,使原本不兼容的接口能够一起工作,提高了类的复用性和系统的灵活性。通过对象适配器和类适配器两种实现方式,展示了适配器模式的代码应用,并讨论了其优点、缺点以及适用场景。
|
5月前
|
设计模式
适配器模式-大话设计模式
适配器模式-大话设计模式
|
4月前
|
设计模式 Go 数据处理
iLogtail设计模式问题之在iLogtail中,为何需要使用适配器模式
iLogtail设计模式问题之在iLogtail中,为何需要使用适配器模式
|
4月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 适配器模式
js设计模式【详解】—— 适配器模式
31 0