13 设计模式之外观模式(家庭影院案例)

news/2024/12/4 22:00:52/

一、什么是外观模式

1.定义

        在日常生活中,许多人喜欢通过遥控器来控制家中的电视、音响、DVD 播放器等设备。虽然这些设备各自独立工作,但遥控器提供了一个简洁的界面,让用户可以轻松地操作多个设备。而这一设计理念正是 外观模式(Facade Pattern) 的核心思想——通过为复杂的子系统提供一个统一的接口,简化客户端与这些子系统的交互。

        外观模式是一种结构型设计模式,旨在为复杂系统中的多个子系统提供一个统一的高层接口,使得客户端可以通过这个接口轻松与各个子系统进行交互,而无需直接处理复杂的实现细节。换句话说,外观模式隐藏了子系统的复杂性,为客户端提供了一个简单的接口。

2.外观模式的关键点:

  • 提供一个高层接口,让客户端通过它与多个子系统交互。
  • 隐藏系统内部的复杂性,简化外部调用。
  • 使得子系统的客户端与子系统之间解耦,降低了系统之间的依赖性。

二、外观模式的应用场景

  • 复杂系统的简化接口:当一个系统包含多个复杂的子系统时,使用外观模式可以将这些复杂的操作封装成一个统一的接口,简化客户端的使用。
  • 系统解耦:如果你不希望系统的客户端直接与各个子系统进行耦合,外观模式提供了一个解耦的方案。通过外观类,客户端不需要了解子系统的内部实现,减少了对系统内部的了解和依赖。

三、外观模式的示例

        接下来,我们通过一个家庭影院系统的例子,来演示外观模式的应用。我们设想有一个家庭影院系统,包含多个设备:电视、音响和 DVD 播放器。每个设备有不同的控制方法,用户需要通过多个操作来启动或关闭它们。为了简化操作,我们可以通过外观模式将这些操作封装成一个统一的接口。

1.设备类

java">// 电视类
public class TV {public void on() {System.out.println("电视打开了");}public void off() {System.out.println("电视关上了");}
}// 音响类
public class SoundSystem {public void on() {System.out.println("音响开了");}public void off() {System.out.println("音响关了");}
}// DVD 播放器类
public class DVDPlayer {public void on() {System.out.println("DVD 播放器开了");}public void off() {System.out.println("DVD 播放器关了");}public void play() {System.out.println("播放电影...");}public void stop() {System.out.println("停止播放...");}
}

2.外观类:

java">// 家庭影院外观类
public class HomeTheaterFacade {private TV tv;private SoundSystem soundSystem;private DVDPlayer dvdPlayer;public HomeTheaterFacade(TV tv, SoundSystem soundSystem, DVDPlayer dvdPlayer) {this.tv = tv;this.soundSystem = soundSystem;this.dvdPlayer = dvdPlayer;}// 观看电影public void watchMovie() {tv.on();soundSystem.on();dvdPlayer.on();dvdPlayer.play();System.out.println("电影已经播放");}// 停止电影public void stopMovie() {tv.off();soundSystem.off();dvdPlayer.off();dvdPlayer.stop();System.out.println("电影已经关闭");}
}

3.客户端代码:

java">// 测试外观模式
public class TestFacade {public static void main(String[] args) {// 创建设备实例TV tv = new TV();SoundSystem soundSystem = new SoundSystem();DVDPlayer dvdPlayer = new DVDPlayer();// 创建家庭影院外观实例HomeTheaterFacade facade = new HomeTheaterFacade(tv, soundSystem, dvdPlayer);// 使用外观类操作设备facade.watchMovie();facade.stopMovie();}
}

4.输出结果

电视打开了
音响开了
DVD 播放器开了
播放电影...
电影已经播放
电视关上了
音响关了
DVD 播放器关了
停止播放...
电影已经关闭


四、外观模式的组成

1.组成部分:

  • 外观类(Facade Class)

    外观类是外观模式的核心,负责定义一个统一的高层接口,提供给客户端调用。它封装了子系统的复杂操作,使得客户端能够通过这个接口与多个子系统进行交互。外观类通常通过组合和调用子系统类来实现对外的简化接口。

  • 子系统类(Subsystem Classes)

    子系统类是一些具体的类,它们实现了系统的业务逻辑。子系统类的职责比较具体,负责实际的功能实现。外观类通过委托的方式,向这些子系统发出请求。子系统类之间通常是彼此独立的,外观类负责协调它们的调用。

  • 客户端(Client)

    客户端通过外观类提供的接口来访问系统。客户端不需要了解子系统类的复杂性,只需要通过外观类进行操作,从而实现对整个系统的控制。

2.组成关系:

  • 外观类:提供一个简单的接口,简化客户端与子系统的交互。
  • 子系统类:实现具体的业务逻辑,但它们不暴露给客户端,客户端通过外观类与它们交互。
  • 客户端:只与外观类交互,通过外观类简化对系统的操作。

3.外观模式的工作流程:

  • 客户端通过外观类提供的简化接口发出请求
  • 外观类负责协调并调用一个或多个子系统类来完成请求
  • 子系统类执行具体的操作,并将结果返回给外观类
  • 外观类将子系统操作的结果返回给客户端

五、外观模式的优缺点:

1.优点:

  • 简化客户端代码:客户端只需要通过外观类提供的简单接口来控制复杂的子系统,而不需要直接操作各个子系统,极大简化了客户端的调用。
  • 解耦外观模式通过提供一个统一的接口,减少了客户端与子系统之间的依赖,使得客户端与子系统的耦合度降低。
  • 易于扩展:如果将来要添加新的设备(如投影仪、蓝光播放器等),只需要对外观类进行扩展,而不需要修改客户端的代码,符合开放封闭原则。

2.缺点:

  • 外观类可能变得臃肿:如果有大量的子系统,外观类可能会变得非常庞大,承担过多的职责,变成“胖外观类”,这时可以考虑使用多个外观类来分担责任。
  • 隐藏了子系统功能外观模式的简化接口虽然易于使用,但也隐藏了子系统的一些功能。如果客户端需要更多的控制或者定制化操作,可能就无法通过外观类来实现,必须直接与子系统交互。

六、总结

        外观模式是一种非常实用的设计模式,适用于需要简化复杂系统接口的场景。它通过为复杂的子系统提供一个统一的、高层次的接口,使得客户端能够通过简单的调用来完成复杂的任务。使用外观模式,我们可以提高系统的可维护性、可扩展性,并且让客户端代码更加简洁易懂。

        通过本文的家庭影院系统示例,我们可以看到外观模式如何将多个设备的控制操作集中到一个外观类中,减少了客户端的操作复杂度。如果你在实际项目中遇到类似的情况,可以考虑使用外观模式来简化系统的操作接口。 


        希望这篇文章能帮助你理解外观模式的应用和实现!如果你有任何问题,或者希望进一步探讨其他设计模式,欢迎随时联系我!


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

相关文章

vue前端 下载、预览图片

前端vue,后端java。 建议使用post请求 api.jsDownloadFileById: (config, params) > {return service.post("api/GridFS/DownloadFileById",config,params);}, a.vue页面 /*** 获取图片* responseType: "arraybuffer" 【必传】指定后端返回的是 arr…

力扣 LCR训练计划2(剑指 Offer 22. 链表中倒数第k个节点)-140

LCR训练计划2(剑指 Offer 22. 链表中倒数第k个节点)-140 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(in…

JavaScript实现tab栏切换

JavaScript实现tab栏切换 代码功能概述 这段代码实现了一个简单的选项卡(Tab)切换功能。它通过操作 HTML 元素的类名(class)来控制哪些选项卡(Tab)和对应的内容板块显示,哪些隐藏。基本思路是先…

解决`-bash: ./configure:/bin/sh^M:解释器错误: 没有那个文件或目录`的问题

解决`-bash: ./configure:/bin/sh^M:解释器错误: 没有那个文件或目录`的问题 一、错误原因分析二、解决方法方法一:使用`dos2unix`工具方法二:使用`sed`命令方法三:使用`tr`命令方法四:在文本编辑器中转换方法五:在Windows系统中使用适当的工具三、预防措施四、总结在使…

深度学习基础03_BP算法(下)过拟合和欠拟合

目录 一、BP算法(下) 0、反向传播代码回顾 写法一: 写法二(更常用): 1、BP中的梯度下降 1.数学描述 2.传统下降方式 3.优化梯度下降方式 指数加权平均 Momentum AdaGrad RMSProp Adam(常用) 总结 二、过拟合和欠拟合 1、概念 1.过拟合 …

第 44 章 - Go语言 团队协作

在第44章中,我们将探讨团队协作的关键方面,包括版本控制系统、代码仓库管理和团队沟通与协作。为了具体化这些概念,我们将结合实际案例,并使用Go语言作为示例语言来演示如何有效地进行团队开发。 1. 版本控制系统 (Version Contr…

Go快速入门

一、环境安装 1、源码包下载 https://golang.org/dl/ https://golang.google.cn/dl/ https://studygolang.com/dl/ 2、下载解压至/usr/local tar -zxvf go1.14.4.linux-amd64.tar.gz -c /usr/local 3、cd /usr/local/go src 源码 bin go指令 gofmt指令 4、配置bin到环境…

【机器学习】支持向量机SVR、SVC分析简明教程

关于使用SVM进行回归分析的介绍很少,在这里,我们讨论一下SVR的理论知识,并对该方法有一个简明的理解。 1. SVC简单介绍 SVR全称是support vector regression,是SVM(支持向量机support vector machine)对回…