当前位置: 首页 > news >正文

设计模式之外观模式(Facade)

一、外观模式介绍

       外观模式( Facade Pattern),也叫门面模式,是一个 “结构型” 设计模式。

       外观模式的原始定义是:为子系统中的一组接口提供统一的接口。它定义了一个更高级别

       的接口,使子系统更易于使用。

       外观模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容

       易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体

       的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

       外观模式有点类似之前讲到的迪米特法则(最少知识原则)和接口隔离原则:两个有交互

       的系统,只暴露有限的必要的接口,如下图所示:

               

       如上图所示,外观类Facade充当了系统中的"服务员",它为多个业务类的调用提供了一个

       统一的入口,简化了类与类之间的交互,如果没有门面类,每个客户类需要和多个子系统之间

       进行复杂的交互,系统的耦合度将会很大

二、外观模式原理

       外观(Facade)模式包含以下主要角色:

                1)外观(Facade)角色:为多个子系统对外提供一个共同的接口。

                     外观角色中可以知道多个相关的子系统中的功能和责任。在正常情况下,它将所

                     有从客户端发来的请求委派到相应的子系统,传递给相应的子系统对象处理

                2)子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访

                      问它。

                      每一个子系统可以是一个类也可以是多个类的集合;每一个子系统都可以被客户

                      端直接调用,或者被外观角色调用;子系统并不知道外观的存在,对于子系统而言,

                      外观角色仅仅是另一个客户端而已

       外观模式类图如下:

                

       外观模式用代码描述如下:

               即外观模式基础代码   

/******************************************************** 子系统A* *******************************************************/
public class SubSystemA {public void methodA(){//业务代码}
}/******************************************************** 子系统B********************************************************/
public class SubSystemB {public void methodB(){//业务代码}
}/******************************************************** 子系统C* *******************************************************/
public class SubSystemC {public void methodC(){//业务代码}
}/******************************************************** 外观角色* 在外观类中操作各个子系统,而Client客户端只操作外观类Facade* *******************************************************/
public class Facade {private SubSystemA sa = new SubSystemA();private SubSystemB sb = new SubSystemB();private SubSystemC sc = new SubSystemC();public void method(){sa.methodA();sb.methodB();sc.methodC();}
}/******************************************************** 测试* 测试作为客户端,只操作外观类* *******************************************************/
public class Test {public static void main(String[] args) {Facade facade = new Facade();facade.method();}
}

三、外观模式应用示例

       以智能家居为例来学习下 外观模式的使用;

       具体需求是:

               通过智能音箱来控制室内的 灯、电视、空调;本来每个设备都需要进行独立的开关操

               作,现在通过智能音箱完成对这几个设备的统一控制 

       类图如下:

               

       具体代码如下:

/********************************************************* 以智能家居为例来学习下 外观模式的使用;*具体需求是:*    通过智能音箱来控制室内的 灯、电视、空调;本来每个设备都需要进行独立的开关操*    作,现在通过智能音箱完成对这几个设备的统一控制 ** 灯类--子系统* *******************************************************/
public class Light {public void on(){System.out.println("打开灯......");}public void off(){System.out.println("关闭灯......");}
}/******************************************************** 电视类--子系统********************************************************/
public class TV {public void on(){System.out.println("打开电视......");}public void off(){System.out.println("关闭电视......");}
}/******************************************************** 空调类--子系统* *******************************************************/
public class AirCondition {public void on(){System.out.println("打开空调......");}public void off(){System.out.println("关闭空调......");}}/******************************************************** 音响类--外观角色* *******************************************************/
public class SmartAppliancesFacade {private Light light;private TV tv;private AirCondition airCondition;public SmartAppliancesFacade() {this.light =new Light();this.tv = new TV();this.airCondition = new AirCondition();}public void say(String message){if(message.contains("打开")){on();}else if(message.contains("关闭")){off();}else{System.out.println("对不起没有听清楚您说什么! 请重新再说一遍");}}//起床后 语音开启 电灯 电视 空调private void on() {System.out.println("起床了!");light.on();tv.on();airCondition.on();}//睡觉前 语音关闭 电灯 电视 空调private void off() {System.out.println("睡觉了!");light.off();tv.off();airCondition.off();}}/******************************************************** 客户端测试类********************************************************/
public class Client {public static void main(String[] args) {//创建外观对象SmartAppliancesFacade facade = new SmartAppliancesFacade();facade.say("打开家电");facade.say("关闭家电");}
}

四、外观模式总结

1、外观模式优点

      1)它对客户端屏蔽了子系统组件,减少了客户端所需要处理的对象数目,并使子系统使

           用起来更加的容易;通过引入外观模式,客户端代码将变得很简单,与之关联的对象也很少

      2)它实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的

           客户端,只需要调整外观类即可

      3)一个子系统的修改对其他子系统没有任何影响,而子系统内部变化也不会影响到外观对象

2、外观模式缺点

      1)不能很好的控制客户端直接使用子系统类,如果客户端访问子系统类做太多的限制则减少

            了可变性和灵活性

      2)如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则

3、外观模式适用场景

      1)简化复杂系统。

            比如,当我们开发了一整套的电商系统后(包括订单、商品、支付、会员等系统),

            我们不能让用户依次使用这些系统后才能完成商品的购买,而是需要一个门户网站

            或手机 App 这样简化过的门面系统来提供在线的购物功能

      2)减少客户端处理的系统数量。

            比如,在 Web 应用中,系统与系统之间的调用可能需要处理 Database 数据库、Model

            业务对象等,其中使用 Database 对象就需要处理打开数据库、关闭连接等操作,然后转

            换为 Model 业务对象,实在是太麻烦了。如果能够创建一个数据库使用的门面(其实就是

            常说的 DAO 层),那么实现以上过程将变得容易很多。

      3)让一个系统(或对象)为多个系统(或对象)工作。

            比如,线程池 ThreadPool 就是一个门面模式,它为系统提供了统一的线程对象的创建、

            销毁、使用等。

      4)联合更多的系统来扩展原有系统。

            当我们的电商系统中需要一些新功能时,比如,人脸识别,我们可以不需要自行研发,

            而是购买别家公司的系统来提供服务,这时通过门面系统就能方便快速地进行扩展。

      5)作为一个简洁的中间层。

            门面模式还可以用来隐藏或者封装系统中的分层结构,同时作为一个简化的中间层来使

            用。比如,在秒杀、库存、钱包等场景中,我们需要共享有状态的数据时(如商品库存、

            账户里的钱),在不改变原有系统的前提下,通过一个中间的共享层(如将秒杀活动的

            商品库存总数统一放在 Redis 里),就能统一进行各种服务(如,秒杀详情页、商品详

           情页、购物车等)的调用。

相关文章:

设计模式之外观模式(Facade)

一、外观模式介绍 外观模式( Facade Pattern),也叫门面模式,是一个 “结构型” 设计模式。 外观模式的原始定义是:为子系统中的一组接口提供统一的接口。它定义了一个更高级别 的接口,使子系统更易于使用。 外观模式,是…...

解锁 Python 嵌套字典的奥秘:高效操作与实战应用指南

文章目录 前言🍀一、 什么是 Python 字典?1.1 字典的语法 🍀二、 字典的基本操作2.1 字典的创建2.2 访问字典中的值2.3 添加或修改键值对2.4 删除字典中的键值对 🍀三、 字典的遍历操作3.1 遍历字典的键3.2 遍历字典的值3.3 同时遍…...

联想服务器配置阵列、安装操作系统

文章目录 [toc]1.配置阵列2.制作启动盘3.安装系统 1.配置阵列 1.根据提示进入BIOS设置(F1) 2.系统设置 3.存储 4.第四步可以看到raid卡信息 5.Main Menu 6.Configuration Management 7.Create Virtual Drive 8.Select RAID Level raid5 9.Select Drives…...

【深度强化学习】DDPG实现的4个细节(OUNoise等)

文章目录 前言一、论文内容简述创新点(特点,与DQN的区别):可借鉴参数:细节补充: 二、细节1:weight_decay原理代码 三、细节2:OUNoise原理代码 四、细节3:ObsNorm原理代码…...

算法工程师重生之第二十二天(递增子序列 全排列 全排列 II 重新安排行程 N皇后 解数独 总结 )

参考文献 代码随想录 一、非递减子序列 给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素,如出现两个整数相等,也可以视作…...

css的选择器及优先级

一、css选择器 CSS选择器是用来选择HTML文档中的元素,并为它们应用样式规则的工具。CSS选择器有很多种,可以根据元素的类名、ID、属性、伪类、伪元素、标签等来选择元素。以下是一些常见的CSS选择器及其用法: 1. ID选择器: 根据…...

JavaScript中的数组不改变原数组的方法

数组 var a [1, 2, 3, 5, 8, 13, 21] 不改变原数组的方法 length 数组元素的长度 继承自原型 concat(arrayX,arrayY) 合并两个或多个数组,返回新数组 合并,a.concat(b) var a[1,2,3],b[4,5,6],c[7,8,9]; a.concat(b,c); //[1, 2, 3, 4, 5, 6, 7…...

Go语言实现长连接并发框架 - 路由分组

文章目录 前言接口结构体接口实现项目地址最后 前言 你好,我是醉墨居士,我们上篇博客实现了任务执行流的路由模块,接下来我们实现一下对任务执行流进行任务 接口 trait/router_group.go type RouterGroup interface {RouterGroup(flow ..…...

跨 VLAN 通信

跨 VLAN 通信指的是不同 VLAN 之间的网络设备进行数据交换的能力。由于 VLAN 将网络分割成多个逻辑隔离的广播域,默认情况下,不同 VLAN 之间的设备无法直接通信。为了实现跨 VLAN 通信,需要借助一些网络设备和技术。以下详细讲解跨 VLAN 通信…...

11.4 Linux_线程_条件变量

概述 条件变量的作用: 条件变量和互斥量配合使用,主要应用于生产者和消费者问题。 这种问题也是一种临界资源的问题,但与互斥量一文中 "写文件" 这种资源不同。文件是一直存在的临界资源,而生产者的资源不是一直存在…...

通信工程学习:什么是IP网际协议

IP:网际协议 IP网际协议(Internet Protocol,简称IP)是整个TCP/IP协议栈中的核心协议之一,它负责在网络中传送数据包,并提供寻址和路由功能。以下是对IP网际协议的详细解释: 一、对IP网际协议的…...

github 国内文件加速下载

参看;https://www.cnblogs.com/ting1/p/18356265 在源网址前加上 https://hub.gitmirror.com/ 或https://mirror.ghproxy.com/,例如: https://hub.gitmirror.com/https://github.com/t1m0thyj/WinDynamicDesktop/releases/download/v5.4.1/WinDynamicD…...

算法6:模拟运算

文章目录 z字形变幻外观数列数青蛙 题目均来自于力扣 z字形变幻 class Solution { public:string convert(string s, int numRows) {int n s.size();if(n < numRows || numRows 1) return s;int d 2 * numRows - 2;string res;for(int j 0; j < n; j d){res s[j]; …...

【网络协议大花园】应用层 http协议的使用小技巧,用好了都不用加班,效率翻两倍(上篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…...

今日指数day8实战补充(上)

1.用户管理 1.多条件综合查询 1.1 多条件综合查询接口说明 1&#xff09;原型效果 2&#xff09;接口说明 功能描述&#xff1a;多条件综合查询用户分页信息&#xff0c;条件包含&#xff1a;分页信息 用户创建日期范围 服务路径&#xff1a;/api/users 服务方法&#xff1…...

Python 之进阶语法:with...as...

1. Python with…as…是什么 Python 的 with…as… 语句&#xff0c;就像一个贴心的管家&#xff0c;负责照顾你的资源&#xff0c;让你不再担心忘记关闭文件、网络连接或数据库事务等。这个管家在你进入“房间”时自动打开门&#xff0c;离开时帮你把门关上&#xff0c;真的是…...

嵌入式硬件设计知识详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

计算机网络:物理层 —— 信道及其极限容量

文章目录 信道信道的极限容量信号失真失真类型产生信号失真的主要因素 奈式准则码元传输速率香农公式 信道 信道是指信息传输的通道或介质。在通信中&#xff0c;信道扮演着传输信息的媒介的角色&#xff0c;将发送方发送的信号传递给接收方。 信道可以是无线信道&#xff0c…...

面向对象特性中 继承详解

目录 概念&#xff1a; 定义&#xff1a; 定义格式 继承关系和访问限定符 基类和派生类对象赋值转换&#xff1a; 继承中的作用域&#xff1a; 派生类的默认成员函数 继承与友元&#xff1a; 继承与静态成员&#xff1a; 复杂的菱形继承及菱形虚拟继承&#xff1a; 虚…...

C++ | Leetcode C++题解之第455题分发饼干

题目&#xff1a; 题解&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int m g.size(), n s.size();int count 0;for (int i 0, j 0; i < …...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...