13 设计模式之外观模式(家庭影院案例)
一、什么是外观模式?
1.定义
在日常生活中,许多人喜欢通过遥控器来控制家中的电视、音响、DVD 播放器等设备。虽然这些设备各自独立工作,但遥控器提供了一个简洁的界面,让用户可以轻松地操作多个设备。而这一设计理念正是 外观模式(Facade Pattern) 的核心思想——通过为复杂的子系统提供一个统一的接口,简化客户端与这些子系统的交互。
外观模式是一种结构型设计模式,旨在为复杂系统中的多个子系统提供一个统一的高层接口,使得客户端可以通过这个接口轻松与各个子系统进行交互,而无需直接处理复杂的实现细节。换句话说,外观模式隐藏了子系统的复杂性,为客户端提供了一个简单的接口。
2.外观模式的关键点:
- 提供一个高层接口,让客户端通过它与多个子系统交互。
- 隐藏系统内部的复杂性,简化外部调用。
- 使得子系统的客户端与子系统之间解耦,降低了系统之间的依赖性。
二、外观模式的应用场景
- 复杂系统的简化接口:当一个系统包含多个复杂的子系统时,使用外观模式可以将这些复杂的操作封装成一个统一的接口,简化客户端的使用。
- 系统解耦:如果你不希望系统的客户端直接与各个子系统进行耦合,外观模式提供了一个解耦的方案。通过外观类,客户端不需要了解子系统的内部实现,减少了对系统内部的了解和依赖。
三、外观模式的示例
接下来,我们通过一个家庭影院系统的例子,来演示外观模式的应用。我们设想有一个家庭影院系统,包含多个设备:电视、音响和 DVD 播放器。每个设备有不同的控制方法,用户需要通过多个操作来启动或关闭它们。为了简化操作,我们可以通过外观模式将这些操作封装成一个统一的接口。
1.设备类
// 电视类
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.外观类:
// 家庭影院外观类
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.客户端代码:
// 测试外观模式
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.缺点:
- 外观类可能变得臃肿:如果有大量的子系统,外观类可能会变得非常庞大,承担过多的职责,变成“胖外观类”,这时可以考虑使用多个外观类来分担责任。
- 隐藏了子系统功能:外观模式的简化接口虽然易于使用,但也隐藏了子系统的一些功能。如果客户端需要更多的控制或者定制化操作,可能就无法通过外观类来实现,必须直接与子系统交互。
六、总结
外观模式是一种非常实用的设计模式,适用于需要简化复杂系统接口的场景。它通过为复杂的子系统提供一个统一的、高层次的接口,使得客户端能够通过简单的调用来完成复杂的任务。使用外观模式,我们可以提高系统的可维护性、可扩展性,并且让客户端代码更加简洁易懂。
通过本文的家庭影院系统示例,我们可以看到外观模式如何将多个设备的控制操作集中到一个外观类中,减少了客户端的操作复杂度。如果你在实际项目中遇到类似的情况,可以考虑使用外观模式来简化系统的操作接口。
希望这篇文章能帮助你理解外观模式的应用和实现!如果你有任何问题,或者希望进一步探讨其他设计模式,欢迎随时联系我!
相关文章:
13 设计模式之外观模式(家庭影院案例)
一、什么是外观模式? 1.定义 在日常生活中,许多人喜欢通过遥控器来控制家中的电视、音响、DVD 播放器等设备。虽然这些设备各自独立工作,但遥控器提供了一个简洁的界面,让用户可以轻松地操作多个设备。而这一设计理念正是 外观模…...
单片机学习笔记 12. 定时/计数器_定时
更多单片机学习笔记:单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…...
Web安全基础实践
实践目标 (1)理解常用网络攻击技术的基本原理。(2)Webgoat实践下相关实验。 WebGoat WebGoat是由著名的OWASP负责维护的一个漏洞百出的J2EE Web应用程序,这些漏洞并非程序中的bug,而是故意设计用来讲授We…...
Zookeeper集群数据是如何同步的?
大家好,我是锋哥。今天分享关于【Zookeeper集群数据是如何同步的?】面试题。希望对大家有帮助; Zookeeper集群数据是如何同步的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper集群中的数据同步是通过一种称为ZAB(Zo…...
SpringCloud框架学习(第六部分:Sentinel实现熔断与限流)
目录 十四、SpringCloud Alibaba Sentinel实现熔断与限流 1.简介 2.作用 3.下载安装 4.微服务 8401 整合 Sentinel 入门案例 5.流控规则 (1)基本介绍 (2)流控模式 Ⅰ. 直接 Ⅱ. 关联 Ⅲ. 链路 (3࿰…...
动态规划-----路径问题
动态规划-----路径问题 下降最小路径和1:状态表示2:状态转移方程3 初始化4 填表顺序5 返回值6 代码实现 总结: 下降最小路径和 1:状态表示 假设:用dp[i][j]表示:到达[i,j]的最小路径 2:状态转…...
Rust循环引用与多线程并发
循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中,由于所有权和生命周期的严格约束,直接创建循环引用通常会导致编译失败。例如: // 错误的循环引用示例 struct Node {next: Option<B…...
东方隐侠网安瞭望台第8期
谷歌应用商店贷款应用中的 SpyLoan 恶意软件影响 800 万安卓用户 迈克菲实验室的新研究发现,谷歌应用商店中有十多个恶意安卓应用被下载量总计超过 800 万次,这些应用包含名为 SpyLoan 的恶意软件。安全研究员费尔南多・鲁伊斯上周发布的分析报告称&…...
底部导航栏新增功能按键
场景需求: 在底部导航栏添加power案件,单击息屏,长按 关机 如下实现图 借此需求,需要掌握技能: 底部导航栏如何实现新增、修改、删除底部导航栏流程对底部导航栏部分样式如何修改。 比如放不下、顺序排列、坑点如…...
C++ 之弦上舞:string 类与多样字符串操作的优雅旋律
string 类的重要性及与 C 语言字符串对比 在 C 语言中,字符串是以 \0 结尾的字符集合,操作字符串需借助 C 标准库的 str 系列函数,但这些函数与字符串分离,不符合 OOP 思想,且底层空间管理易出错。而在 C 中࿰…...
centos8:Could not resolve host: mirrorlist.centos.org
【1】错误消息: [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …...
Linux 定时任务 命令解释 定时任务格式详解
目录 时间命令 修改时间和日期 定时任务格式 定时任务执行 查看定时任务进程 重启定时任务 时间命令 #查看时间 [rootlocalhost ~]# date 2021年 07月 23日 星期五 14:38:19 CST --------------------------------------- [rootlocalhost ~]# date %F 2021-07-23 -----…...
aws(学习笔记第十五课) 如何从灾难中恢复(recover)
aws(学习笔记第十五课) 如何从灾难中恢复 学习内容: 使用CloudWatch对服务器进行监视与恢复区域(region),可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…...
github webhooks 实现网站自动更新
本文目录 Github Webhooks 介绍Webhooks 工作原理配置与验证应用云服务器通过 Webhook 自动部署网站实现复制私钥编写 webhook 接口Github 仓库配置 webhook以服务的形式运行 app.py Github Webhooks 介绍 Webhooks是GitHub提供的一种通知方式,当GitHub上发生特定事…...
【C语言】递归的内存占用过程
递归 递归是函数调用自身的一种编程技术。在C语言中,递归的实现会占用内存栈(Call Stack),每次递归调用都会在栈上分配一个新的 “栈帧(Stack Frame)”,用于存储本次调用的函数局部变量、返回地…...
365天深度学习训练营-第P6周:VGG-16算法-Pytorch实现人脸识别
🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 文为「365天深度学习训练营」内部文章 参考本文所写记录性文章,请在文章开头带上「👉声明」 🍺要求: 保存训练过…...
企业AI助理在数据分析与决策中扮演的角色
在当今这个数据驱动的时代,企业每天都需要处理和分析大量的数据,以支持其业务决策。然而,面对如此庞大的数据量,传统的数据分析方法已经显得力不从心。幸运的是,随着人工智能(AI)技术的不断发展…...
洛谷 B2029:大象喝水 ← 圆柱体体积
【题目来源】https://www.luogu.com.cn/problem/B2029【题目描述】 一只大象口渴了,要喝 20 升水才能解渴,但现在只有一个深 h 厘米,底面半径为 r 厘米的小圆桶 (h 和 r 都是整数)。问大象至少要喝多少桶水才会解渴。 …...
go每日一题:mock打桩、defer、recovery、panic的调用顺序
题目一:单元测试中使用—打桩 打桩概念:使用A替换 原函数B,那么A就是打桩函数打桩原理:运行时,通过一个包,将内存中函数的地址替换为桩函数的地址打桩操作:利用Patch()函…...
STM32F103 HSE时钟倍频以及设置频率函数(新手向,本人也是新手)
HSE_SetSysCLK是野火教程里的,不懂的去这 16-RCC(第3节)使用HSE配置系统时钟并使用MCO输出监控系统时钟_哔哩哔哩_bilibili HSE_AutoSetHSE的算法部分是自己写的,用了一个转接数组。C语言不支持bool所以自己定义了一个boolK代替bool。 AutoHSE.h: /**…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
