【设计模式】外观模式(门面模式)

外观模式(Facade Pattern)详解


一、外观模式简介

外观模式(Facade Pattern) 是一种 结构型设计模式,它为一个复杂的子系统提供一个统一的高层接口,使得子系统更容易使用。

外观模式又称为门面模式,它是一种对象结构型模式。

简单来说,外观模式就像是一个“总控中心”或“门面”,它屏蔽了子系统的复杂性,对外提供一个简单的调用方式。这样客户端不需要了解内部细节,只需要通过这个“门面”来操作整个系统。

外观模式也是“迪米特法则”的体现。

引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。

在这里插入图片描述
模式结构
在这里插入图片描述

在这里插入图片描述
外观模式包含如下角色
Facade: 外观角色
SubSystem:子系统角色


二、解决的问题类型

  • 问题背景:当系统中存在多个相互依赖、结构复杂的类和接口时,客户端直接使用这些类会变得非常麻烦,容易出错。
  • 解决方案:外观模式通过引入一个中间层(即外观类),将这些复杂的交互封装起来,让客户端只需与外观类打交道即可完成一系列操作。

三、使用场景

  1. 简化复杂系统的访问:当你有一个由多个对象组成的子系统,但希望给用户一个简单的接口来使用这个系统。
  2. 解耦客户端与子系统:客户端不关心子系统内部如何工作,只关心结果。
  3. 分层设计:在多层架构中,外观常用于表现层与业务逻辑层之间,作为接口抽象层。

四、实际生活案例

想象你在家里使用一个智能音箱说:“我回家了”。这时:

  • 灯自动打开
  • 空调启动
  • 音乐播放器开始播放你喜欢的音乐
  • 电视自动打开

你并不需要手动去操作每一个设备,而是通过一句话触发了一个“回家模式”。这个“回家模式”就是外观类,它封装了所有设备的操作,对外提供一个统一的入口。


五、代码案例

典型的外观角色代码:

public class Facade
{private SubSystemA obj1 = new SubSystemA();private SubSystemB obj2 = new SubSystemB();private SubSystemC obj3 = new SubSystemC();public void method(){obj1.method();obj2.method();obj3.method();}
} 

场景描述:

我们模拟一个家庭影院系统,包括以下几个子系统:

  • 投影仪(Projector)
  • 音响(Amplifier)
  • 蓝光播放器(BluRayPlayer)
  • 灯光控制(Lights)

我们要通过一个 HomeTheaterFacade 来统一管理这些组件,让客户可以通过一个接口轻松地开启/关闭观影模式。


子系统类定义:

// 投影仪类
class Projector {public void on() {System.out.println("Projector is ON");}public void setWideScreenMode() {System.out.println("Projector in widescreen mode (16x9)");}public void off() {System.out.println("Projector is OFF");}
}// 音响类
class Amplifier {public void on() {System.out.println("Amplifier is ON");}public void setVolume(int level) {System.out.println("Setting volume to " + level);}public void off() {System.out.println("Amplifier is OFF");}
}// 蓝光播放器类
class BluRayPlayer {public void on() {System.out.println("BluRay Player is ON");}public void play(String movie) {System.out.println("Playing movie: " + movie);}public void stop() {System.out.println("BluRay Player stopped");}public void off() {System.out.println("BluRay Player is OFF");}
}// 灯光控制类
class Lights {public void dim(int level) {System.out.println("Lights dimmed to " + level + "% brightness");}public void on() {System.out.println("Lights are ON");}public void off() {System.out.println("Lights are OFF");}
}

案例二:

外观类实现(Java):

// 家庭影院外观类
class HomeTheaterFacade {private Projector projector;private Amplifier amplifier;private BluRayPlayer bluRayPlayer;private Lights lights;public HomeTheaterFacade(Projector projector, Amplifier amplifier,BluRayPlayer bluRayPlayer, Lights lights) {this.projector = projector;this.amplifier = amplifier;this.bluRayPlayer = bluRayPlayer;this.lights = lights;}// 开启观影模式public void watchMovie(String movie) {System.out.println("Preparing to watch a movie...");lights.dim(10);          // 调暗灯光projector.on();          // 打开投影仪projector.setWideScreenMode(); // 设置宽屏模式amplifier.on();          // 打开音响amplifier.setVolume(85); // 设置音量bluRayPlayer.on();       // 启动蓝光播放器bluRayPlayer.play(movie); // 播放电影}// 关闭观影模式public void endMovie() {System.out.println("Shutting movie time down...");bluRayPlayer.stop();bluRayPlayer.off();amplifier.off();projector.off();lights.on(); // 灯光恢复}
}

客户端测试类:

public class Client {public static void main(String[] args) {// 创建各个子系统对象Projector projector = new Projector();Amplifier amplifier = new Amplifier();BluRayPlayer player = new BluRayPlayer();Lights lights = new Lights();// 创建外观对象HomeTheaterFacade homeTheater = new HomeTheaterFacade(projector, amplifier, player, lights);// 使用外观开启观影模式homeTheater.watchMovie("Inception");System.out.println("\n------------------------------\n");// 使用外观结束观影模式homeTheater.endMovie();}
}

输出结果示例:

Preparing to watch a movie...
Lights dimmed to 10% brightness
Projector is ON
Projector in widescreen mode (16x9)
Amplifier is ON
Setting volume to 85
BluRay Player is ON
Playing movie: Inception------------------------------Shutting movie time down...
BluRay Player stopped
BluRay Player is OFF
Amplifier is OFF
Projector is OFF
Lights are ON

六、优点总结

优点描述
简化客户端调用客户端无需了解子系统细节,只需调用外观类方法即可
降低耦合度客户端与子系统解耦,便于后期维护和扩展
提高可维护性修改子系统行为时,只需修改外观类,不影响客户端
支持模块化设计符合高内聚低耦合的设计原则

七、缺点

不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。

在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

八、与其他模式对比(补充)

模式名称目标
适配器模式解决接口不兼容问题,强调转换
代理模式控制对某个对象的访问,强调保护或增强
外观模式封装子系统复杂性,强调简化接口调用

九、小结

  • 外观模式适用于:需要将一组复杂子系统整合成一个简单接口供外部使用的场景。
  • 核心思想是:隐藏实现细节,提供统一、简洁的接口。
  • 作为开发人员,掌握外观模式有助于我们更好地进行模块划分、系统集成和接口设计。

如果你正在开发一个大型系统,比如支付系统、订单系统、视频会议系统等,合理使用外观模式可以大大提升系统的可读性和可维护性。

如需进一步了解其他设计模式,欢迎继续提问!

十、扩展内容

  • 一个系统有多个外观类:在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。
  • 不要试图通过外观类为子系统增加新行为:不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。
  • 外观模式与迪米特法则:外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。
  • 抽象外观类的引入:外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。
    抽象外观类的引入
    在这里插入图片描述
    部分内容由AI生成注意识别!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90815.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【6.1.1 漫画分库分表】

漫画分库分表 “数据量大了不可怕,可怕的是不知道如何优雅地拆分。” 🎭 人物介绍 架构师老王:资深数据库架构专家,精通各种分库分表方案Java小明:对分库分表充满疑问的开发者ShardingSphere师傅:Apache S…

Tomcat问题:启动脚本startup.bat中文乱码问题解决

一、问题描述 我们第一次下载或者打开Tomcat时可能在控制台会出现中文乱码问题二、解决办法 我的是8.x版本的tomcat用notepad打开:logging.properties 找到:java.util.logging.ConsoleHandler.encoding设置成GBK,重启tomcat即可

Linux中Gitee的使用

一、Gitee简介:Gitee(码云)是中国的一个代码托管和协作开发平台,类似于GitHub或GitLab,主要面向开发者提供代码管理、项目协作及开源生态服务。适用场景个人开发者:托管私有代码或参与开源项目。中小企业&a…

Oracle大表数据清理优化与注意事项详解

一、性能优化策略 1. 批量处理优化批量大小选择: 小批量(1,000-10,000行):减少UNDO生成,但需要更多提交次数中批量(10,000-100,000行):平衡性能与资源消耗大批量(100,000行):适合高配置环境,但需监控资源使…

Anaconda及Conda介绍及使用

文章目录Anaconda简介为什么选择 Anaconda?Anaconda 安装Win 平台macOS 平台Linux 平台Anaconda 界面使用Conda简介Conda下载安装conda 命令环境管理包管理其他常用命令Jupyter Notebook(可选)Anaconda简介 Anaconda 是一个数据科学和机器学…

外包干了一周,技术明显退步

我是一名本科生,自2019年起,我便在南京某软件公司担任功能测试的工作。这份工作虽然稳定,但日复一日的重复性工作让我逐渐陷入了舒适区,失去了前进的动力。两年的时光匆匆流逝,我却在原地踏步,技术没有丝毫…

【QT】多线程相关教程

一、核心概念与 Qt 线程模型 1.线程与进程的区别: 线程是程序执行的最小单元,进程是资源分配的最小单元,线程共享进程的内存空间(堆,全局变量等),而进程拥有独立的内存空间。Qt线程只要关注同一进程内的并发。 2.为什么使用多线程…

VS 版本更新git安全保护问题的解决

问题:我可能移动了一个VS C# 项目,然后,发现里面的git版本检测不能用了 正在打开存储库: X:\Prj_C#\3D fatal: detected dubious ownership in repository at X:/Prj_C#/3DSnapCatch X:/Prj_C#/3D is owned by:S-1-5-32-544 but the current …

Git常用命令一览

Git 是基于 Linux内核开发的版本控制工具。与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持(ps:这得分是用什么样的服务端,使用http协议或者git协议等不太一样。并且在…

基于 JSON 文件定位图片缺陷点并保存

基于JSON的图片缺陷处理流程 ├── 1. 输入检查 │ ├── 验证图片文件是否存在 │ └── 验证JSON文件是否存在 │ ├── 2. 数据加载 │ ├── 打开并加载图片 │ └── 读取并解析JSON文件 │ ├── 3. 缺陷信息提取 │ ├── 检查JSON中是否存在shapes字…

Redis基础学习(五大值数据类型的常用操作命令)

目录 一、Redis基本知识与Redis键(key)常用操作命令。 二、Redis的五大值的数据类型。(value) 三、Redis关于键(key)的值常用操作指令表格统计。 (1)字符串(String&#…

Ubuntu——办公软件 LibreOffice 安装与使用指南

十四、LibreOffice 安装与使用1、核心组件组件​​​​图标​​​​对应MS Office​​​​核心功能定位​​​​Writer​​📝Word专业文档处理与排版​​Calc​​📊Excel数据计算与分析​​Impress​​🎬PowerPoint演示文稿制作​​Draw​​&…

Securecrt丢失tab以及终端重新配色

今天在使用 Securecrt 的时候,发现 Securecrt 的 tab 标签消失不见了,仔细回想起来,应该是上一次误按了 alt enter 最大化,然后导致配置丢失的问题 还有表现就是菜单中的 Session Tabs 无论勾选还是不勾选都没有任何变化&#xf…

frp搭建内网穿透教程

frp搭建内网穿透教程 步骤1:准备工作 公网服务器:需要一台具有公网IP的服务器作为中转服务器,安装frp服务器端(frps)。内网设备:需要暴露服务的内网设备,安装frp客户端(frpc&#xf…

【JavaEE进阶】图书管理系统(未完待续)

目录 用户登录 添加图书 图书列表 修改图书 删除图书 批量删除 拦截器 🍃前言 什么是拦截器? 拦截器的基本使用 自定义拦截器 注册配置拦截器 拦截路径 拦截器执行流程 项目实现统一拦截 定义拦截器 注册配置拦截器 前⾯图书管理系统, 咱们只完成了⽤⼾登录和图书列…

基于同花顺API的熊市与牛市识别模型开发及因子分析

基于同花顺API的熊市与牛市识别模型开发及因子分析 1. 引言 1.1 研究背景与意义 金融市场中的牛市与熊市识别一直是投资者和研究人员关注的重点问题。牛市(Bull Market)通常指价格持续上涨的市场环境,投资者信心充足,交易活跃;而熊市(Bear Market)则指价格持续下跌的市场…

AMD 锐龙 AI MAX+ 395 处理器与端侧 AI 部署的行业实践

2025 年 7 月 10 日,AMD 在深圳召开 Mini AI 工作站行业解决方案峰会,正式发布基于锐龙 AI MAX 395 处理器的端侧 AI 部署方案,与 200 余家生态伙伴共同探讨 AI 技术在千行百业的落地路径。这一硬件平台通过异构计算架构与开放生态设计&#…

期权盘位是什么意思?

本文主要介绍期权盘位是什么意思?“期权盘位”并非金融交易中的标准术语,可能是口语化表达或对某些概念的简化描述。期权盘位是什么意思?1. 期权盘口的“价位”(买卖报价位置)在期权交易中,“盘口”通常指实…

【Trea】Trea国内版|国际版|海外版下载|Mac版|Windows版|Linux下载配置教程

【Trea】Trea国内版|国际版|海外版下载|Mac版|Windows版下载配置教程 本文适用读者: 想要第一次安装 Trea需要在 Windows 或 macOS 上完成环境配置想深入了解 Doubao、DeepSeek、ChatGPT、Claude 等模型在 Trea 中的接…

MyBatis实现分页查询-苍穹外卖笔记

首先分页查询的原理是SQL的limit关键字。LIMIT 子句用于限制 SQL 查询返回的记录数。它接受一个或两个整数参数,第一个参数表示偏移量,第二个参数表示返回的最大记录数。我们完全可以使用前端传给我们的page,pageSize,自己去计算limit的参数,…