Java设计模式 _结构型模式_适配器模式

server/2024/10/8 15:32:40/

一、适配器模式

**1、适配器模式(Adapter Pattern)**是一种结构型设计模式。适配器类用来作为两个不兼容的接口之间的桥梁,使得原本不兼容而不能一起工作的那些类可以一起工作。譬如:读卡器就是内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取或写入数据到内存卡。

2、实现思路
总的来说:实现业务类注入适配器中,适配器注入调用类中。调用类使用适配器的方法,适配器使用实现业务类的方法。
具体步骤如下:
(1)、创建适配器类(Adapter),实现和业务类(Computer)相同的功能接口(Abilities)
(2)、适配器类注入功能接口(Abilities)的属性类。重写构造方法,根据传入或其他参数实例化这个属性类
(3)、适配器类实现功能接口(Abilities)的抽象方法,通过自身的属性类去实现调用。
(4)、在业务类(Computer)中,注入适配器类(Adapter)的属性类,重写构造方法实例化适配器。
(5)、在业务类中,使用适配器的实现方法替换原本自身的实现方法。

二、代码示例

1、示例1
电脑(Computer),内存卡(MemoryCard),读卡器(ReadCardAdapter)。电脑通过读卡器完成对内存卡数据的读取和写入。
代码示例:

java">// 定义规范超类,读取数据,写入数据的接口
public interface Abilities {// 读取数据public void readData();// 存储数据public void storeData();
}
// 定义内存卡类
public class MemoryCard implements Abilities{@Overridepublic void readData() {System.out.println("读取了内存卡数据");}@Overridepublic void storeData() {System.out.println("数据存储到内存卡");}
}
// 定义适配器类,需要实例具体的业务类
public class CardReaderAdapter implements Abilities {private MemoryCard memoryCard;public CardReaderAdapter(MemoryCard memoryCard){this.memoryCard = memoryCard;}@Overridepublic void readData() {memoryCard.readData();}@Overridepublic void storeData() {memoryCard.storeData();}
}
// 定义电脑类,注入适配器类
public class Computer implements Abilities{private CardReaderAdapter cardReaderAdapter;public Computer(CardReaderAdapter cardReaderAdapter){this.cardReaderAdapter =cardReaderAdapter;}@Overridepublic void readData() {cardReaderAdapter.readData();}@Overridepublic void storeData() {cardReaderAdapter.storeData();}
}
// 测试
public class Ztest {public static void main(String[] args) {MemoryCard memoryCard = new MemoryCard();CardReaderAdapter adapter = new CardReaderAdapter(memoryCard);Computer computer = new Computer(adapter);computer.readData();computer.storeData();}
}

运行结果:
在这里插入图片描述
上图可以看出,虽然实现的是电脑的实例对象,调用的确实内存卡的业务实现方法。说明适配器生效了。

2、示例2
原本的音频播放器(AudioPlayer),仅支持播放mp3,现在需要扩展播放wav格式和pcm格式的文件
最初代码示例:

java">// 定义规范超类,播放文件的接口
public interface Abilities {void play(String name);
}
// 定义音频播放器类,播放mp3文件
public class AudioPlayer implements Abilities {@Overridepublic void play( String name) {String type = name.substring(name.indexOf(".")+1);if ("mp3".equals(type)) {System.out.println("原生播放器播放:" + name);} else {System.out.println("不支持的格式!");}}
}
// 测试
public class Ztest {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("青花瓷.mp3");audioPlayer.play("鸟语花香.wav");}
}

运行结果
在这里插入图片描述
可以看到目前仅支持播放mp3的文件,其他格式不支持播放。

改造思路:
编写扩展的实例类,通过注入适配器,将适配器注入原始类的方法,实现原始类可以调用自身方法或者适配器方法的多种情形。
在这里插入图片描述

使用适配器修改后,代码示例如下:

java">// 定义规范超类,播放文件的接口
public interface Abilities {void play(String name);
}
// 创建播放wav格式的实例类,实现超类
public class WavPlayer implements Abilities {@Overridepublic void play(String name) {System.out.println("Wav播放器播放:" + name);}
}
// 创建播放pcm格式的实例类,实现超类
public class PcmPlayer implements Abilities {@Overridepublic void play(String name) {System.out.println("Pcm播放器播放:" + name);}}
// 创建适配器类,根据业务场景注入超类的实例,调用注入实例的实现方法
public class AudioAdapter implements Abilities {private Abilities abilitiesPlay;public AudioAdapter(String type) {if ("wav".equals(type)) {this.abilitiesPlay = new WavPlayer();} else if ("pcm".equals(type)) {this.abilitiesPlay = new PcmPlayer();}}@Overridepublic void play(String name) {abilitiesPlay.play(name);}
}
// 修改音频播放器,注入适配器,根据条件选择调用原生方法或者适配器的方法
public class AudioPlayer implements Abilities {private AudioAdapter audioAdapter;@Overridepublic void play(String name) {String type = name.substring(name.indexOf(".") + 1);if ("mp3".equals(type)) {System.out.println("原生播放器播放:" + name);} else if ("wav".equals(type) || "pcm".equals(type)) {audioAdapter = new AudioAdapter(type);audioAdapter.play(name);} else {System.out.println("不支持的格式!");}}
}
// 测试
public class Ztest {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("青花瓷.mp3");audioPlayer.play("青鸟.wav");audioPlayer.play("鼓风机采集声音.pcm");audioPlayer.play("鸟语花香.avi");}
}

运行结果:
在这里插入图片描述
上图可以看到已经支持播放了两种新的格式的文件。

学海无涯苦作舟!!!


http://www.ppmy.cn/server/18378.html

相关文章

c++ 计算引物退火温度

引物(primer)的退火温度(Tm)是指引物与目标DNA序列形成双链DNA的温度。盐浓度、引物长度、引物的碱基序列等都可影响Tm。 本代码参考primer3源码 https://github.com/primer3-org/primer3 // // main.cpp // test3 // // C…

TDengine高可用探讨

提到数据库,不可避免的要考虑高可用HA(High Availability)。但是很多人对高可用的理解并不是很透彻。 要搞清高可用需要回答以下几个问题: 什么是高可用?为什么需要高可用?高可用需要达到什么样的目标&am…

Flink CDC / Kafka Connect 自动转换 Debezium 的 DataTime / Timpstamp 时间格式

不管是用 Flink CDC 还是 Kafka Connect (Debezium Connector),在实时获取数据库的 CDC 数据并以 Json 格式写入 Kafak 中时,都会遇到 DataTime / Timpstamp 类型的转换问题,即:原始数据库中的 DataTime / Timpstamp 的字面量是 2021-12-14 00:00:00 这种形式,但是,转换为…

智慧安防视频监控EasyCVR视频汇聚平台无法自动播放视频的原因排查与解决

国标GB28181协议EasyCVR安防视频监控平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力,平台支持7*24小时实时高清视频监控,能同时播放多路监控视频流…

服务器防护哪家好

在当前的网络安全环境中,服务器防护已经成为企业和个人防御网络威胁的重要一环。选择一个高效且可靠的服务器防护方案是至关重要的。今天我们来看一下为什么安全狗的服务器防护哪家好呢,一起来看看安全狗服务器防护的介绍吧。 首先,安全狗提供…

后端开发大纲

后端3要素: 后端编程语言:java、python等后端框架:spring、django等,降低构建后端程序的难度包管理工具:maven、pip等,别人把代码打包成包供我们调用 域名:重定向到urlREST风格api:请…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release,发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

python 每日一练(11) 回文数

回文数是指正序(从左到右)和倒叙(从右到左)都是一样的整数。列如,1223是回文,而1222不是回文。 解法一: 通过逆转字符进行比较 首先考虑临界问题,提高判断效率。 如果x是一个负数…