【HeadFirst系列之HeadFirst设计模式】第8天之适配器模式与外观模式:让不兼容的接口和谐共处!

news/2025/2/23 1:38:35/

适配器模式外观模式:让不兼容的接口和谐共处!

大家好!今天我们来聊聊设计模式中的适配器模式(Adapter Pattern)和外观模式(Facade Pattern)。如果你曾经遇到过接口不兼容的问题,或者希望简化复杂系统的调用方式,那么这两种模式就是你的救星!本文基于《Head First 设计模式》的适配器模式外观模式章节,通过生动的故事和 Java 代码示例,带你轻松掌握这两种模式的精髓。

在这里插入图片描述


1. 适配器模式:让不兼容的接口和谐共处

故事背景

小明开发了一个音乐播放器系统,系统中有一个 MediaPlayer 接口,用于播放音频文件。现有的实现类 AudioPlayer 可以播放 MP3 文件,但无法播放 MP4 和 VLC 文件。

问题出现

小明希望扩展系统,使其支持播放 MP4 和 VLC 文件。然而,MP4 和 VLC 文件的播放逻辑由第三方库提供,接口与 MediaPlayer 不兼容。

解决方案:适配器模式

小明决定使用适配器模式,将第三方库的接口适配成 MediaPlayer 接口,从而在不修改现有代码的情况下扩展系统功能。

代码实现

1. 定义目标接口
// 目标接口:MediaPlayer
interface MediaPlayer {void play(String audioType, String fileName);
}
2. 实现现有类
// 现有类:AudioPlayer
class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing MP3 file: " + fileName);} else {System.out.println("Unsupported audio type: " + audioType);}}
}
3. 定义第三方接口
// 第三方接口:AdvancedMediaPlayer
interface AdvancedMediaPlayer {void playMp4(String fileName);void playVlc(String fileName);
}// 具体实现类:Mp4Player
class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playMp4(String fileName) {System.out.println("Playing MP4 file: " + fileName);}@Overridepublic void playVlc(String fileName) {// Do nothing}
}// 具体实现类:VlcPlayer
class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playMp4(String fileName) {// Do nothing}@Overridepublic void playVlc(String fileName) {System.out.println("Playing VLC file: " + fileName);}
}
4. 实现适配器
// 适配器类:MediaAdapter
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer.playMp4(fileName);}}
}
5. 扩展现有类
// 扩展后的 AudioPlayer
class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing MP3 file: " + fileName);} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("Unsupported audio type: " + audioType);}}
}
6. 客户端代码
public class MusicPlayerApp {public static void main(String[] args) {MediaPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "song.mp3"); // 输出: Playing MP3 file: song.mp3audioPlayer.play("mp4", "movie.mp4"); // 输出: Playing MP4 file: movie.mp4audioPlayer.play("vlc", "video.vlc"); // 输出: Playing VLC file: video.vlcaudioPlayer.play("avi", "video.avi"); // 输出: Unsupported audio type: avi}
}

2. 外观模式:简化复杂系统的调用方式

故事背景

小明开发了一个家庭影院系统,系统中包含多个设备,比如 DVD 播放器投影仪音响等。每次看电影时,小明需要依次打开这些设备,操作非常繁琐。

问题出现

小明希望简化操作,只需调用一个方法就能完成所有设备的准备工作。

解决方案:外观模式

小明决定使用外观模式,将多个设备的操作封装成一个统一的接口,从而简化调用方式。

代码实现

1. 定义子系统类
// DVD 播放器
class DvdPlayer {public void on() {System.out.println("DVD Player is on");}public void play(String movie) {System.out.println("Playing movie: " + movie);}public void off() {System.out.println("DVD Player is off");}
}// 投影仪
class Projector {public void on() {System.out.println("Projector is on");}public void wideScreenMode() {System.out.println("Projector is in widescreen mode");}public void off() {System.out.println("Projector is off");}
}// 音响
class SoundSystem {public void on() {System.out.println("Sound System is on");}public void setVolume(int level) {System.out.println("Sound System volume set to " + level);}public void off() {System.out.println("Sound System is off");}
}
2. 实现外观类
// 外观类:HomeTheaterFacade
class HomeTheaterFacade {private DvdPlayer dvdPlayer;private Projector projector;private SoundSystem soundSystem;public HomeTheaterFacade(DvdPlayer dvdPlayer, Projector projector, SoundSystem soundSystem) {this.dvdPlayer = dvdPlayer;this.projector = projector;this.soundSystem = soundSystem;}public void watchMovie(String movie) {System.out.println("Get ready to watch a movie...");dvdPlayer.on();projector.on();projector.wideScreenMode();soundSystem.on();soundSystem.setVolume(10);dvdPlayer.play(movie);}public void endMovie() {System.out.println("Shutting down the home theater...");dvdPlayer.off();projector.off();soundSystem.off();}
}
3. 客户端代码
public class HomeTheaterApp {public static void main(String[] args) {DvdPlayer dvdPlayer = new DvdPlayer();Projector projector = new Projector();SoundSystem soundSystem = new SoundSystem();HomeTheaterFacade homeTheater = new HomeTheaterFacade(dvdPlayer, projector, soundSystem);homeTheater.watchMovie("Inception"); // 输出: Get ready to watch a movie...homeTheater.endMovie(); // 输出: Shutting down the home theater...}
}

3. 总结

  • 适配器模式:用于解决接口不兼容的问题,通过适配器将不兼容的接口转换为目标接口。
  • 外观模式:用于简化复杂系统的调用方式,通过外观类封装多个子系统的操作。

这两种模式都能帮助我们更好地设计系统,提高代码的可维护性和扩展性。希望本文的讲解和代码示例能帮助你更好地理解适配器模式外观模式


互动话题
你在项目中用过适配器模式外观模式吗?遇到过哪些问题?欢迎在评论区分享你的经验!


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

相关文章

【登月计划】 DAY2 中期:产品研发与设计验证(4-6)--《设计图纸如何从电脑飞进生产线?揭秘研发系统的 “暗箱操作”》

目录 四、乐高教学:拆解 CAD/CAE 与 PLM 的 “共生关系” 1. CAD 系统:工程师的 “数字画笔” 🎨 2. CAE 系统:产品的 “虚拟实验室” 🔬 3. PLM 系统:设计的 “大管家” 五、装逼话术:设计…

Lineageos 22.1(Android 15)Launcer打开Taskbar

一、前言 Taskbar是Android高版本给大屏幕设备定制的快捷导航条,屏幕宽度或者高度达到一定程度,就会判断为平板而显示taskbar。 /*** Returns {code true} if the bounds represent a tablet.*/public boolean isTablet(WindowBounds bounds) {return s…

使用 Docker-compose 部署 MySQL

使用 Docker Compose 部署 MySQL 本文将详细指导如何使用 docker-compose 部署 MySQL,包括基本配置、启动步骤、数据持久化以及一些高级选项。通过容器化部署 MySQL,你可以快速搭建一个隔离的数据库环境,适用于开发、测试或小型生产场景。 关…

Linux相关命令

Linux相关知识 1.名词介绍2.Linux 文件基本属性1.Linux文件属主和属组2.更改文件属性1.chgrp:更改文件属组2.chown:更改文件所有者(owner),也可以同时更改文件所属组。3.chmod:更改文件9个属性 3. Linux 文…

Spring AI + Ollama 实现调用DeepSeek-R1模型API

一、前言 随着人工智能技术的飞速发展,大语言模型(LLM)在各个领域的应用越来越广泛。DeepSeek 作为一款备受瞩目的国产大语言模型,凭借其强大的自然语言处理能力和丰富的知识储备,迅速成为业界关注的焦点。无论是文本生…

数据库-SQLite

目录 1.SQLite介绍 2.SQLite特性 3.SQLite使用 3.1.环境准备 3.2.创建数据库文件 3.3.操作数据库 4.API接口 4.1.封装数据库句柄结构体 4.2.数据库句柄初始化 4.3.连接数据库 4.4.创建表 插入数据 修改数据 删除数据 4.5.执行查询语句 4.6.初始化存储查询结果句柄 …

【Gin-Web】Bluebell社区项目梳理2:JWT-Token认证

本文目录 一、JWTHeaderPayloadSignature 二、代码解析刷新Token鉴权中间件 一、JWT JWT是Json Web Token的缩写。JWT本身是没有定义任何技术实现,只是定义了一种基于Token的会话管理规则,涵盖Token需要包含的标准内容和Token生成过程,特别适…

Rust 中的 `Drop` 特性:自动化资源清理的魔法

一、自动清理机制:Rust 的析构函数 在许多语言中,当程序结束或对象不再需要时,开发者必须显式调用清理函数来释放内存或关闭资源。Rust 则不然——它通过 Drop 特性实现了类似析构函数(destructor)的自动化清理机制。…