第七章结构性模式—适配器模式

news/2025/2/16 3:11:44/

文章目录

  • 适配器模式
    • 解决的问题
    • 概念
    • 结构
  • 类适配器模式
  • 对象适配器模式
  • 接口适配器模式
  • 应用场景
    • JDK 源码 - Reader 与 InputStream

结构型模式描述如何将类或对象按某种布局组成更大的结构,有以下两种:

  • 类结构型模式:采用继承机制来组织接口和类。
  • 对象结构型模式:釆用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系耦合度低,满足 “合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下 7 种:

  • 代理模式
  • 适配器模式
  • 装饰者模式
  • 桥接模式
  • 外观模式
  • 组合模式
  • 享元模式

适配器模式

解决的问题

img

  • 比如我们插头的电流和手机需要的电流是不一样的,我们不能直接使用,所以需要充电器来转换电流,我们的充电器就是类似适配器,将两个不兼容的东西兼容到一起用
  • 也比如我们的聋哑人是不能听到我们说话的,手语翻译员将我们的话翻译为手语,然后聋哑人可以“听懂我们说话”,手语翻译员就是我们的适配器

概念

定义:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

  • 适配器模式分为类适配器模式对象适配器模式,前者由于类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

结构

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期望访问的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
    • 适配者类,其实是要被适配到目标接口的类。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

类适配器模式

实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件

  • 实现业务接口,继承已有组件

【例】读卡器

现有一台电脑只能读取 SD 卡,而要读取 TF 卡中的内容的话就需要使用到适配器模式。

创建一个读卡器,将 TF 卡中的内容读取出来,类图如下:

image-20230504092203455

  • SDCard 是目标接口,它是 Computer 所期望访问的接口
  • TFCard 是适配者类,它将会被适配到 Computer 可以访问的 SDCard
  • SDAdapterTF 是适配器类,它实现让目标访问 SDCard 却达到 TFCard 的功能。

目标接口—SDCard和其实现类

public interface SDCard {String readSD();// 往SD卡中写数据void writeSD(String msg);
}
public class SDCardImpl implements SDCard{@Overridepublic String readSD() {String msg = "sd card read a msg :hello word SD";return msg;}@Overridepublic void writeSD(String msg) {System.out.println("sd card write msg : " + msg);}
}

适配者接口—TFCard和其实现类

public interface TFCard {public String readTF();public void writeTF(String msg);
}
public class TFCardImpl implements TFCard{@Overridepublic String readTF() {String msg = "TFCard read msg: hello word TFCard";return msg;}@Overridepublic void writeTF(String msg) {System.out.println("TFCard write msg: " + msg);}}

适配器类

public class SDAdapterTF extends TFCardImpl implements SDCard{@Overridepublic String readSD() {System.out.println("adapter read tf card");return readTF();}@Overridepublic void writeSD(String msg) {System.out.println("adapter write tf card");writeTF(msg);}
}
  • 继承我们的适配者实现类和实现其目标接口
    • 继承我们的适配者实现类是为了能够调用其中的对应的方法
    • 实现其目标接口是为了起到适配的效果

类适配器模式违背了合成复用原则,类适配器是客户类有一个接口规范的情况下可用,反之不可用。

对象适配器模式

实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。

实现业务接口,引入已有组件

改造后的适配器类

public class SDAdapterTF implements SDCard {private TFCard tfCard;public SDAdapterTF(TFCard tfCard) {this.tfCard = tfCard;}@Overridepublic String readSD() {System.out.println("adapter read tf card");return tfCard.readTF();}@Overridepublic void writeSD(String msg) {System.out.println("adapter write tf card");tfCard.writeTF(msg);}
}
  • 不是通过继承适配者类来获取对应的方法,而是使用其对象来调用对应的方法

测试

public class Client {public static void main(String[] args) {// 创建计算机对象Computer computer = new Computer();// 电脑读取SD卡中的数据(可直接读)String msg = computer.readSD(new SDCardImpl());System.out.println(msg);System.out.println("===============");// 使用电脑读取TF卡中的数据(无法直接读)// 创建适配器类对象SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImpl());String s = computer.readSD(sdAdapterTF);System.out.println(s);}
}
  • 通过构造方法来给适配器传入对应的适配者类的实例对象

接口适配器模式

当不希望实现一个接口中所有的方法时,可以创建一个抽象类 Adapter 实现接口所有方法,然后只需要继承该抽象类即可。

应用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

JDK 源码 - Reader 与 InputStream

  • 解码:字节数据 -> 字符数据
  • 编码:字符数据 -> 字节数据

image-20230504103651731

Reader(字符流)、InputStream(字节流)之间适配使用的是 InputStreamReader。(表面上是这样)

InputStreamReader 继承自 java.io 包中的 Reader,对他中的抽象的未实现的方法给出实现。如:

public int read() throws IOException {return sd.read();
}public int read(char cbuf[], int offset, int length) throws IOException {return sd.read(cbuf, offset, length);
}

从上图可以看出:

  • InputStreamReader 是对同样实现了 Reader 的 StreamDecoder 的封装。

  • StreamDecoder 不是 Java SE API 中的内容,是 Sun JDK 给出的自身实现,它对构造方法中的字节流类(InputStream)进行封装,并通过该类进行了字节流和字符流之间的解码转换。

结论:

  • 表面看,InputStreamReader 做了 InputStream 字节流类到 Reader 字符流之间的转换。
  • 而从如上 Sun JDK 中的实现类关系结构中可以看出,是 StreamDecoder 在设计实现上采用了适配器模式。
    • StreamDecoder 就是对应的适配器类
    • Reader是对应的目标接口,只是这里不是接口,而是对应的抽象方法
    • InputStream是对应的适配类,在我们StreamDecoder中聚合了对应的适配类对象,也就是对应的对象适配器模式

http://www.ppmy.cn/news/67821.html

相关文章

MySQL 数据库面试题

TOC 1. MySQL 的内连接、左连接、右连接有有什么区别? inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集。 left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记…

在 PHP 7 中不要做的 10 件事

1. 不要使用 mysql_ 函数 这一天终于来了,从此你不仅仅“不应该”使用mysql_函数。PHP 7 已经把它们从核心中全部移除了,也就是说你需要迁移到好得多的mysqli_函数,或者更灵活的 PDO 实现。 2. 不要编写垃圾代码 这一条可能易于理解&#…

BM64-最小花费爬楼梯

题目 给定一个整数数组 cost,其中 cost[i] 是从楼梯第i个台阶向上爬需要支付的费用,下标从0开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到楼梯顶部的…

探索iOS之AVFoundation框架

AVFoundation框架的业务层主要是AVKit和UIKit,内核层包括CoreVideo、CoreAudio、CoreMedia、VideoToolBox等。AVFoundation作为iOS的音视频框架,提供音视频播放、录制、编辑、编解码、音效设置等。接下来,让我们看一下整体的框架图。 一、AVK…

最新入河排污口设置论证、水质影响预测与模拟、污水处理工艺分析及典型建设项目入河排污口方案报告书实例分析

随着水资源开发利用量不断增大,全国废污水排放量与日俱增,部分河段已远远超出水域纳污能力。近年来,部分沿岸入河排污口设置不合理,超标排污、未经同意私设排污口等问题逐步显现,已威胁到供水安全、水环境安全和水生态安全&#x…

C++基础之默认成员函数(构造函数,析构函数)

目录 空类中都有什么 默认成员函数 构造函数 简介 特性 注意 总结 析构函数 简介 特性 注意 总结 空类中都有什么 先看下面一段代码&#xff1a; class Date {};int main() {Date d1;std::cout << sizeof(Date) << std::endl;std::cout << sizeof(d1) <…

2.App换肤框架实现原理

换肤的案例有哪些? 网易云音乐的换肤App的节日换肤,比如:双11、618等 达到的怎样的效果? 换肤过程中不闪烁app无需重新启动架构独立 (换肤的逻辑在一个单独的module中完成)无需继承 (采用AOP思想,让换肤与我们业务的Activity分离,不需要在BaseActivity中集成换肤逻辑代码,…

618大促即将来临,速卖通、Lazada等平台如何快速提高排名和转化率?

速卖通每年三大促&#xff0c;328、618、双11。618马上就要来临&#xff0c;卖家朋友们都准备好了吗&#xff1f;今天陈哥就和大家聊聊怎么快速提高产品转化率。转化率是卖家在分析复盘时非常关键的因素&#xff0c;转化率的高低直接影响着卖家目前的关键词listing或者商品描述…