【设计模式深度剖析】【6】【结构型】【外观模式】| 以电脑开关按钮为例,并结合微服务架构的API网关加深理解
👈️上一篇:桥接模式 | 下一篇:享元模式👉️
设计模式-专栏👈️
目 录
- 外观模式(Facade Pattern)
- 定义
- 英文原文
- 直译
- 如何理解呢?
- 字面理解
- 代码实现中的理解
- 生活案例:操作多功能料理机
- 典型案例分析:API网关与外观模式
- 外观模式角色
- UML类图
- 外观(Facade)
- 子系统(Subsystem)
- 客户(Client)
- 代码示例
- 子系统角色:SubsystemOne
- 子系统角色:SubsystemTwo
- 外观角色:Facade
- 客户端角色:Client
- 外观模式的应用
- 外观模式的优点
- 外观模式的缺点
- 外观模式的使用场景
- 示例解析:电脑开关按钮
- 代码示例
- UML类图
- 子系统角色:电脑内部的复杂组件
- 外观类(电源开关按钮)
- 客户端
外观模式(Facade Pattern)
外观模式(Facade Pattern),如同一位精明的“外交官”,它简化了客户端与复杂子系统之间的交互,通过提供一个统一的“外交”接口,使得客户端无需深究子系统内部的“政治斗争”,从而降低了系统的复杂度,提高了代码的可维护性和可读性。
==>本文示例源码,点击查看👈️<==
定义
英文原文
Facade Pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
直译
外观模式为子系统中的一组接口提供了一个统一的接口。外观定义了一个更高层次的接口,使得子系统更加容易使用。
如何理解呢?
字面理解
外观即外表、外观面,是事物对外展示的一面。
代码实现中的理解
在代码实现中,外观角色就像是系统的“外表”,它隐藏了内部的子系统细节,为客户端提供了一个统一的接口来访问子系统。
生活案例:操作多功能料理机
想象一下,当我们正在使用一个复杂的厨房设备,比如多功能料理机。这个料理机内部可能包含了榨汁机、搅拌机、研磨机等多种功能。
但是,我们并不需要直接操作这些功能,只需要通过一个简单的控制面板就能完成我们想要的操作。
这个控制面板就是外观模式的一个实际应用。它隐藏了料理机内部的复杂性,为我们提供了一个简单、直观的操作方式。
同样地,在软件系统中,外观模式也为我们隐藏了复杂的内部结构和交互,使得我们能够更加方便地使用系统。
典型案例分析:API网关与外观模式
微服务架构中的API网关,为客户端提供了统一的访问入口,是进入系统的唯一节点,这与外观模式的定义相符。API网关封装了内部系统的架构,并且提供API给各个客户端。
网关处理非业务逻辑(如认证、授权、负载均衡、缓存、熔断、降级、限流等),使得业务微服务更加专注于业务实现。
具体表现为:
-
隐藏后端服务的复杂性
在微服务架构中,后端通常包含多个独立的服务,每个服务都有自己的接口、功能和数据。这些服务之间可能存在复杂的依赖关系和交互逻辑。API网关作为一个中间件,隐藏了这些复杂性,为前端提供了一个统一、简洁的接口。前端开发者无需为每一个后端微服务单独配置地址和端口,只需要知道API网关的地址即可。因此,前端开发者无需关心后端服务的具体实现和部署情况,只需与API网关进行交互即可。
-
服务聚合
当一个前端请求需要多个后端微服务协同处理时,API网关可以聚合这些微服务的响应,并将结果合并后返回给前端。
API网关能够隐藏后端服务的复杂性,这减少了前端的复杂性,为前端提供一个简洁的响应,使得前端能够专注于与用户的交互和展示逻辑。
-
统一接口和协议
API网关为前端提供了统一的接口和协议,使得前端开发者能够以统一的方式与后端服务进行通信。这样,即使后端服务的接口发生变化或新增了服务,只要API网关的接口保持不变,前端代码就无需修改。这种统一性减少了前端与后端之间的耦合度,使得前端可以更加灵活地与后端进行交互。
-
认证和授权
API网关可以实施身份验证和授权机制,确保只有合法的用户、经过认证的请求才能访问后端服务。
它可以通过OAuth2.0、JWT等技术实现用户认证和令牌管理,保护后端服务免受非法访问。API网关成为安全性的守护者,为后端服务提供一层保护。
-
限流和熔断:
API网关可以对流量进行限制,防止后端服务因过载而崩溃。
当某个微服务出现故障时,API网关可以自动熔断对该微服务的调用,避免故障扩散到其他服务,避免级联故障的发生。
API网关能够控制和管理后端服务的访问,确保系统的稳定性和可靠性。
-
路由和请求转发
API网关能够根据预设的路由规则,将前端的请求转发到后端对应的服务上。这种路由机制使得前端无需关心后端服务的具体地址和端口,只需发送请求到API网关即可。同时,API网关还可以根据服务的负载情况、健康状况等因素进行负载均衡和容错处理,进一步降低前端与后端之间的耦合度。
-
负载均衡
一个网关可以接收多个服务实例,因此网关需要在各个对等的服务实例上做负载均衡策略。
-
降低服务间的耦合度
通过将非业务逻辑(如路由、转发、认证、授权、熔断、限流等)放在API网关中实现,可以使得后台业务微服务更加专注于业务逻辑的实现,实现业务与技术的解耦。
通过API网关的路由转发机制,前端与后端之间的耦合度被大大降低。前端开发者无需关心后端服务的具体实现和部署情况,只需与API网关进行交互即可。同时,后端服务无需直接关注前端发送的具体请求细节,包括请求的参数、格式等,同时也无需直接处理针对前端的响应格式。它们只需按照与API网关或其他服务调用者约定的接口规范,处理接收到的请求数据,并返回符合规范的数据格式。
-
日志和监控:
API网关可以记录所有经过的请求日志,方便后续的故障排查、性能分析和安全审计。
收集API的调用量、响应时间、错误率等关键指标,为系统监控和性能调优提供数据支持。
通过外观模式的实现,API网关在前后端分离的微服务架构中发挥着至关重要的作用。它简化了前端的配置和开发过程,提高了系统的可扩展性、可靠性和安全性。同时,API网关还提供了路由、认证、限流、监控等核心功能,使得微服务架构更加完善和高效。
外观模式角色
UML类图

外观(Facade)
为子系统中的一组接口提供一个一致的界面,此界面使得这一子系统更加容易使用。
子系统(Subsystem)
实现系统的部分功能,客户可以通过外观角色与其进行交互。
客户(Client)
通过外观角色与子系统交互,使用子系统的功能。
代码示例
子系统角色:SubsystemOne
package com.polaris.designpattern.list2.structural.pattern6.facade.classicdemo;// 子系统角色:SubsystemOne
public class SubsystemOne {public void methodOne() {System.out.println("SubsystemOne: Method 1 executed.");}
}
子系统角色:SubsystemTwo
package com.polaris.designpattern.list2.structural.pattern6.facade.classicdemo;// 子系统角色:SubsystemTwo
public class SubsystemTwo {public void methodTwo() {System.out.println("SubsystemTwo: Method 2 executed.");}
}
外观角色:Facade
package com.polaris.designpattern.list2.structural.pattern6.facade.classicdemo;// 外观角色:Facade
public class Facade {private SubsystemOne subsystemOne;private SubsystemTwo subsystemTwo;public Facade() {subsystemOne = new SubsystemOne();subsystemTwo = new SubsystemTwo();}// 提供单独调用子系统一的方法 public void operationOne() {subsystemOne.methodOne();}// 提供单独调用子系统二的方法 public void operationTwo() {subsystemTwo.methodTwo();}// 提供同时调用两个子系统方法的方法 public void operation() {operationOne();operationTwo();}
}
客户端角色:Client
package com.polaris.designpattern.list2.structural.pattern6.facade.classicdemo;// 客户端角色:Client
public class Client {public static void main(String[] args) {Facade facade = new Facade();// 单独调用子系统一的方法 facade.operationOne();System.out.println("------------------");// 单独调用子系统二的方法 facade.operationTwo();System.out.println("------------------");// 同时调用两个子系统的方法 facade.operation();}
}
/* Output:
SubsystemOne: Method 1 executed.
------------------
SubsystemTwo: Method 2 executed.
------------------
SubsystemOne: Method 1 executed.
SubsystemTwo: Method 2 executed.
*///~
外观模式的应用
外观模式就像是我们日常生活中使用的智能手机界面。手机内部可能包含了各种复杂的硬件和软件,但对外,我们只需要通过一个简单、直观的界面就能完成打电话、发信息、拍照、上网等各种功能。这个界面就是外观模式的一个应用,它隐藏了内部的复杂性,为用户提供了一个统一的、简单的操作方式。
外观模式的优点
- 简化操作:外观模式为用户提供了一个统一的接口,用户无需了解内部复杂的结构,只需通过外观接口就能完成所需的操作。
- 降低耦合度:外观模式使得子系统之间的耦合度降低,因为它们之间的交互都是通过外观接口进行的,而不是直接交互。
- 提高灵活性:当子系统内部发生变化时,只需要修改外观接口的实现,而无需修改客户端代码,提高了系统的灵活性。
外观模式的缺点
- 增加复杂性:在某些情况下,如果设计不当,外观类可能会变得非常复杂,从而增加了系统的复杂性。
- 依赖风险:由于客户端都依赖于外观接口,因此如果外观接口设计不合理或出现问题,可能会导致整个系统的崩溃。
外观模式的使用场景
- 子系统之间交互复杂:当系统内部有多个子系统,并且子系统之间的交互非常复杂时,可以使用外观模式来简化它们之间的交互。
- 需要隐藏子系统细节:在某些情况下,我们可能不希望用户或客户端直接访问子系统的内部细节。此时,可以使用外观模式来隐藏这些细节,只提供一个统一的接口供用户访问。
- 提高系统灵活性和可扩展性:当系统需要经常添加或删除子系统时,使用外观模式可以使得客户端代码不随子系统的变化而变化,从而提高了系统的灵活性和可扩展性。
示例解析:电脑开关按钮
==>本文示例源码,点击查看👈️<==
我们可以使用“电脑开关机”作为一个更简单且常见的外观模式例子。
电脑内部有很多复杂的硬件和软件组件,如处理器、内存、硬盘、操作系统等。但是,当我们想要打开电脑或关闭电脑时,我们并不需要直接与这些组件交互,而是通过一个统一的接口——电源开关按钮来完成。
我们并不需要了解电脑内部复杂的构造和工作原理,只需要按下电源开关按钮,电脑就会开始启动;再次按下按钮,电脑就会关机。
电源开关按钮就是外观模式的一个实际应用,它隐藏了电脑内部复杂的启动和关闭过程,为用户提供了一个简单、直观的操作方式。
代码示例
UML类图

子系统角色:电脑内部的复杂组件
package com.polaris.designpattern.list2.structural.pattern6.facade.computerfacade;// 电脑内部的复杂组件(这里只是示意)
public class ComputerHardware {public void startUp() {System.out.println("Starting up the computer...");// 这里会执行一系列复杂的启动过程,如加载操作系统、初始化硬件等 }public void shutDown() {System.out.println("Shutting down the computer...");// 这里会执行一系列复杂的关闭过程,如保存数据、关闭应用程序、关闭硬件等 }
}
外观类(电源开关按钮)
package com.polaris.designpattern.list2.structural.pattern6.facade.computerfacade;// 外观类(电源开关按钮)
public class PowerButton {private ComputerHardware hardware;public PowerButton() {hardware = new ComputerHardware();}// 统一的接口,用户只需调用此方法即可启动电脑 public void pressToStart() {hardware.startUp();}// 统一的接口,用户只需调用此方法即可关闭电脑 public void pressToShutDown() {hardware.shutDown();}
}
客户端
package com.polaris.designpattern.list2.structural.pattern6.facade.computerfacade;// 客户端代码(用户)
public class User {public static void main(String[] args) {PowerButton powerButton = new PowerButton();powerButton.pressToStart(); // 启动电脑 // ... 用户使用电脑 ... powerButton.pressToShutDown(); // 关闭电脑 }
}/* Output:
Starting up the computer...
Shutting down the computer...
*///~
在这个代码示例中,
ComputerHardware类代表电脑内部的复杂组件,它提供了启动和关闭电脑的方法。
PowerButton类是外观类,它隐藏了电脑内部复杂的启动和关闭过程,并为用户提供了一个统一的接口——电源开关按钮。用户(即客户端)只需要与
PowerButton类交互,就能控制电脑的启动和关闭,而无需关心电脑内部是如何工作的。
👈️上一篇:桥接模式 | 下一篇:享元模式👉️
设计模式-专栏👈️
相关文章:
【设计模式深度剖析】【6】【结构型】【外观模式】| 以电脑开关按钮为例,并结合微服务架构的API网关加深理解
👈️上一篇:桥接模式 | 下一篇:享元模式👉️ 设计模式-专栏👈️ 目 录 外观模式(Facade Pattern)定义英文原文直译如何理解呢?字面理解代码实现中的理解生活案例:操作多功能料理机典型案例…...
2024拼多多 最新理论+实战干货,从入门到精通全链路多角度学习-7节课
基于最新规则理论结合实际的干货 课程内容: 01 2024年多多防比价新规则破局理论课与实操课.mp4 02 24年多多强付费第二节课基础内功.mp4 03 24年多多强付费第三节课直通车实操 .mp4 04 24年多多强付费第一节课市场定价格段,mp4 05 24年多多自然流第一节课市场…...
在Three.js中实现模型点击高亮:整合EffectComposer与OutlinePass的终极指南
效果【后期实现鼠标点击选中轮廓后给出一个弹窗显示相应的模型信息】 标签指示线参考我的上一篇文章 引言 Three.js不仅让WebGL的3D图形编程变得简单易懂,还通过其强大的扩展库支持丰富的后期处理效果,为3D场景增添无限魅力。本篇文章将引导您深入了…...
Webrtc支持HEVC之FFMPEG支持HEVC编解码(一)
一、前言 Webrtc使用的FFMPEG(webrtc\src\third_party\ffmpeg)和官方的不太一样,使用GN编译,各个平台使用了不一样的配置文件 以Windows为例,Chrome浏览器也类似 二、修改配置文件 windows:chromium\config\Chrome\win\x64 其他平台: chromium\config\Chrome\YOUR_SYS…...
高校实验室危险化学品及重大危险源安全管理系统
高校实验室危险化学品及重大危险源安全管理的重要性: 保障师生安全:通过严格管理,可以有效地降低这些风险,确保师生在实验室内的安全。 确保实验教学质量:良好的危化品管理能够确保实验材料的准确性和可靠性࿰…...
【Godot4自学手册】第四十一节背包系统(一)UI设置
各位同学,好久没有更新笔记了,今天开始,我准备自学背包系统。今天先学习下UI界面设置。 一、新建场景和结点 1.新建Node2D场景,命名为Inventory,保存到Scenes目录下,inventory.tscn。 2.新建TextureRect子…...
JS继承的方式
目录 原型链继承构造函数继承组合继承寄生组合继承ES6 Class 继承原型链继承 原理: 通过将子类的原型(prototype)设置为父类的一个实例,使得子类实例能够沿着原型链访问到父类的属性和方法。 function Parent() {this.parentProperty...
拓展虚拟世界边界,云手机可以做到吗
虚拟世界,AI,VR等词汇是21世纪最为流行的词汇,在科技背后,这些词汇的影响变得越来越大,已经走进了人们的世界,比如之前APPLE发布的vision pro,使人们能够更加身临其境的体验到原生os系统&#x…...
网络的功能和实现方法简介
网络的功能: 计算机网络是研究怎么样在两个端用户之间提供访问通路的。所以网络的功能是为网络上的任意两个端用户之间提供访问通路。 计算机通信的特点: 间歇性和突发性。即时而线路中没有信息流过,时而突来的大量数据需要迅速传输。为此计…...
npm有哪些插件包??
1.Web开发相关 Web开发相关的npm插件包涵盖了各种工具、框架和库,帮助开发人员简化开发流程、提高效率并实现更好的用户体验。以下是一些常见的Web开发相关的npm插件包及其功能: 1. webpack:一个现代的JavaScript应用程序的静态模块打包工具…...
SpringBoot基础篇
1:parent 目的:减少依赖配置 开发SpringBoot程序要继承spring-boot-starter-parentspring-boot-starter-parent中定义了若干个依赖管理继承parent模块可以避免多个依赖使用相同技术出现依赖版本冲突继承parent的形式也可以采用引入依赖的i形式实现效果…...
【java11】java11新特性介绍
Java11于2018年9月25日正式发布,Java11是继Java8之后的第一个LTS(Long-Term-Support)长期支持功能版本,与之前的版本(Java9和Java10)不同,它提供了长达3年的维护期,旨在提供稳定且长…...
搜维尔科技:介绍下Manus的OptiTrack 手套,体验精致的每指触觉!
搜维尔科技:介绍下Manus的OptiTrack 手套,体验精致的每指触觉! 搜维尔科技:介绍下Manus的OptiTrack 手套,体验精致的每指触觉!...
Element ui 快速入门(基础知识点)
element ui官网 前言: 在当今时代,我们在编写计算机程序时,不仅仅是写几个增删改查的简单功能,为了满足广大用户对页面美观的需求,为了让程序员们写一些功能更简便,提高团队协作效率,所以eleme…...
[数据集][目标检测]脑肿瘤检测数据集VOC+YOLO格式9787张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):9787 标注数量(xml文件个数):9787 标注数量(txt文件个数):9787 标注…...
兆易创新:周期已至 触底反弹?
韩国那边来的数据啊,4月芯片库存同比下降33.7%,创近10年以来(最)大降幅,芯片出口同比增长53.9%,其中存储芯片出口额同比大幅增长98.7%,开启了涨价模式。沉寂一年多的存储芯片迎来了景气周期。 所…...
【分享】两种方法禁止修改Word文档
对于比较重要的Word文件,不想被随意编辑修改,可以试试以下两个方法,不清楚的小伙伴,一起来看看吧! 方法1:设置“只读方式” 我们可以给Word文档设置以“只读方式”打开,这样就算编辑修改了文档…...
藏品名称:龙凤呈祥摆件
藏品名称:龙凤呈祥摆件 规格:重约 14.3Kg 藏品类别:杂项 此器身布满繁缠纹饰。器表为一轮红日出于东方,照耀辽阔江海。红日旁边有两点黄金凸显其尊贵。一神龙首尾相接有祥云伴随,大山脚下栖息着一只凤凰与神龙遥相呼应。龙身和龙尾交接处有花和花蕊,花开富贵象征着吉祥。整个…...
Ubuntu server 24 (Linux) sudo 免输密码
1 sudo 使用要输入密码,费时费力。 2 sudo命令免输密码,需要修改/etc/sudoers文件 #本文以test用户为例,#允许不需要输入密码执行 sudo vi /etc/sudoers test ALL(ALL) NOPASSWD: ALL %sudo ALL(ALL:ALL) ALL --> #%sudo ALL(ALL:ALL) ALL#所有…...
Qt——控件
目录 概念 QWidget核心属性 enabled geometry WindowFrame的影响 windowTitle windowIcon qrc的使用 windowOpacity cursor font toolTip focusPolicy 编辑 styleSheet 按钮类控件 PushButton RadioButton CheckBox 显示类控件 Label textFormat pixm…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
