设计模式详解(八):外观模式——Facade
目录导航
- 什么是外观模式
- 现实生活类比
- 实战示例
- 门面模式的好处
- 门面模式源码举例
什么是外观模式
外观模式的英文名是Facade,意思是the front of a building,即建筑物的正面(门面),我个人更喜欢翻译成门面模式。门面模式是一种结构型设计模式,所谓结构型是指在代码结构设计方面的设计模式。
门面模式是一个类或一个模块统一的功能入口,屏蔽掉系统内部的实现及运作方式,客户端通过门面与系统交互,大大降低使用的复杂度,减少与系统的耦合。
现实生活类比
在一家餐馆中,顾客可能需要各种服务。如:点餐、买单、询问卫生间、需要卫生纸、临时添加碗筷等等。如果每种服务都要到餐馆不同的服务点找不同的人解决,顾客会疯掉。而前台就是整个餐馆的门面,是餐馆所有功能的输出口,顾客通过前台与餐馆沟通,享受各种服务,而不用关心前台将会对此事如何安排(具体指派何人,以何种方式满足顾客要求等)。
实战示例
假如,我们要开发上述的餐馆功能。
初始阶段,业务相对简单,我们只有点餐与买单的功能。新建一个OrderManager类,
public class OrderManager {//点餐public void order(int tableNo) {System.out.println("table " + tableNo + " has ordered");}//买单public void bill(int tableNo, double dollars) {System.out.println("table " + tableNo + " bill:" + dollars);}
}
调用方使用该功能,
public static void main(String[] args) {//创建订单管理模块OrderManager orderManager = new OrderManager();//下单orderManager.order("001");//结账orderManager.bill("001", 350.00);}
随着业务迭代,我们又提供了一些询问服务,置于QueryService中,
public class QueryService {//卫生间在哪里public String whereToilet(){return "it's xxxxx";}//...
}
随着业务的复杂,我们不断加入新的功能置于新的模块。对于餐馆功能的使用方来说,需要记住每个功能模块对应的类,使用复杂度不断攀升。
public static void main(String[] args) {//创建订单管理模块OrderManager orderManager = new OrderManager();//下单orderManager.order("001");//结账orderManager.bill("001", 350.00);//创建服务问询模块QueryService queryService = new QueryService();//询问厕所queryService.whereToilet();//...}
我们使用门面模式可以解决上述问题。首先,我们创建一个门面类——RestaurantFacade,
此类作为整个餐馆功能入口。
public class RestaurantFacade {private OrderManager orderManager = new OrderManager();private QueryService queryService = new QueryService();//...public OrderManager orderService() {return orderManager;}public QueryService queryService() {return queryService;}//...
}
对于调用方来说,所有的功能我都通过RestaurantFacade一个类获取,不关心也没必要知道其内部的实现和运作方式。
不管该系统后续添加新功能还是删除了旧功能,交互门面不变。
public static void main(String[] args) {//创建门面类RestaurantFacade facade = new RestaurantFacade();//下单facade.orderService().order("001");//结账facade.orderService().bill("001", 350.00);//询问厕所facade.queryService().whereToilet();//...}
在这里,为了进一步方便管理,我们RestaurantFacade对外提供的功能是返回子模块,然后子模块再调用具体功能。这种通常是在业务十分庞大复杂的情况下采取的策略。你也可以直接对外提供具体的功能,而把模块信息封装在门面类内部。
以点餐为例:
public class RestaurantFacade {private OrderManager orderManager = new OrderManager();//...public void order(String tableNo) {orderManager.order(tableNo);}//...
}
调用方代码:
public static void main(String[] args) {//创建门面类RestaurantFacade facade = new RestaurantFacade();//下单facade.order("001");//...}
门面模式的好处
外观模式是一种设计模式,旨在简化复杂系统的接口,提供一个更简单的接口来访问系统的子系统集合。它通过将系统的复杂性隐藏在一个单一的接口背后,使得客户端代码更容易使用。以下是外观模式的几个好处:
-
简化接口: 外观模式提供了一个简化的接口,使得客户端不需要了解系统的复杂性和内部工作原理,只需与外观对象进行交互即可。
-
降低耦合性: 外观模式有助于降低系统中各个子系统之间的耦合度,因为客户端只需与外观对象交互,而不需要直接与子系统交互,从而减少了对子系统的依赖性。
-
隐藏实现细节: 外观模式将系统的内部实现细节隐藏在外部,使得系统更易于维护和修改。如果系统的内部实现发生变化,只需更新外观类而不影响客户端代码。
-
提高易用性: 外观模式使得客户端代码更易于理解和使用,因为它提供了一个简单的接口来访问复杂系统的功能,而无需了解系统的内部复杂性。
-
促进代码组织和管理: 外观模式可以帮助将系统分解为更小的模块,并将这些模块组织成更易于管理和维护的结构。
总的来说,外观模式通过简化接口、降低耦合性、隐藏实现细节、提高易用性以及促进代码组织和管理等方面,可以帮助提高系统的可维护性、可扩展性和可重用性。
门面模式源码举例
门面模式在第三方类库中非常常见。例如Okhttp,我们使用它的功能,基本都是通过OkHttpClient这个类。
//创建门面对象,并进行配置OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS)//链接超时为2秒,单位为秒.writeTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS)//读取超时.build();//执行一个请求 okHttpClient.newCall(new Request.Builder().url("xxxx").build()).execute();
相关文章:
设计模式详解(八):外观模式——Facade
目录导航 什么是外观模式现实生活类比实战示例门面模式的好处门面模式源码举例 什么是外观模式 外观模式的英文名是Facade,意思是the front of a building,即建筑物的正面(门面),我个人更喜欢翻译成门面模式。门面模式…...

R语言绘图 | 双Y轴截断图
教程原文:双Y轴截断图绘制教程 本期教程 本期教程,我们提供的原文的译文,若有需求请回复关键词:20240529 小杜的生信笔记,自2021年11月开始做的知识分享,主要内容是R语言绘图教程、转录组上游分析、转录组…...

使用PNP管控制MCU是否需要复位
这两台用到一款芯片带电池,希望电池还有电芯片在工作的时候插入电源不要给芯片复位,当电池没电,芯片不在工作的时候,插入电源给芯片复位所以使用一个PNP三极管,通过芯片IO控制是否打开复位,当芯片正常工作的…...

二重,三重积分和曲面,曲线积分的关系和区别
这是我在学习完曲面曲线积分概念后容易和二重三重积分混淆而大概总结和区分了一下,如果有错误请大佬指出,多谢!!!...
处理STM32 DMA方式下的HAL_UART_ERROR_ORE错误
1. 检查并调整DMA和UART配置 确保初始化顺序:需要确保USART的CR寄存器UE位开关留到最后打开,即完成USART和DMA的所有配置初始化后再使能USART。这样可以避免初始化顺序不当导致的通信问题。配置合适的DMA缓冲区:确保DMA缓冲区足够大…...

初学者如何对大模型进行微调?
粗略地说,大模型训练有四个主要阶段:预训练、有监督微调、奖励建模、强化学习。 预训练消耗的时间占据了整个训练pipeline的99%,其他三个阶段是微调阶段,更多地遵循少量 GPU 和数小时或数天的路线。预训练对于算力和数据的要求非…...

【Qt知识】disconnect
在Qt框架中,disconnect函数用于断开信号与槽之间的连接。当不再需要某个信号触发特定槽函数时,或者为了防止内存泄漏和重复执行问题,你可以使用disconnect来取消这种关联。disconnect函数的基本用法可以根据不同的需求采用多种形式࿰…...
String,StringBuffer,StringBuilder的区别?
String是不可变的,StringBuffer和StringBuilder是可变的。StringBuffer是线程安全的,StringBuilder是非线程安全的。 String的 是如何实现的 使用拼接字符串,其实只是Java提供的一个语法糖。 其实String的 底层是new 了一个StringBuilde…...
vue基础知识点
一、Vue 1. 简介 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的 JavaScript 框架 它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型 由个人维护:尤雨溪,华人 官网 Vue.js - 渐进…...
正则表达式三
运算符的优先级 相同优先级的从左到右计算,不同优先级,优先级高得先运算。从高到低为: 转义字符: 圆括号或方括号:(),[] 限定符:指限定前面元素的次数如:*,,?,{n},{n,},{n,m} 字符…...

MYSQL数据库细节详细分析
MYSQL数据库的数据类型(一般只需要用到这些) 整型类型:用于存储整数值,可以选择不同的大小范围来适应特定的整数值。 TINYINTSMALLINTMEDIUMINTINTBIGINT 浮点型类型:用于存储带有小数部分的数值,提供了单精度(FLOA…...
vue 将图片url转base64
<img :src"imgList[0]" width"600" error"handleImageError" alt"0" load"onloadImg" />//当图片加载完成时,将图片url转成base64onloadImg(event) {this.urlTobase64(event.target.src, event.target.alt…...

Unity之XR Interaction Toolkit如何使用XRSocketInteractable组件
前言 在虚拟现实(VR)和增强现实(AR)开发中,交互性是提升用户体验的关键。Unity作为一个领先的游戏开发引擎,提供了多种工具支持VR/AR开发。Unity的OpenXR插件扩展了这一功能,提供了更强大和灵活的交互系统。其中一个非常有用的组件是XRSocketInteractable。本文将详细介…...

flutter3-os:基于flutter3.x+dart3+getx手机版os管理系统
flutter3-os-admin跨平台手机后台OS系统。 原创Flutter3.22Dart3.4Getxfl_chart等技术开发仿ios手机桌面OA管理系统。自研栅格化布局引擎、自定义桌面壁纸、小部件、底部Dock菜单、可拖拽悬浮球等功能。 全新自研栅格化OS菜单布局引擎。 使用技术 编辑器:VScode技术…...
C++ 用数组模拟队列
在C中,使用数组模拟队列通常涉及到两个主要的操作:入队(enqueue)和出队(dequeue)。由于数组是一个固定大小的数据结构,当使用数组模拟队列时,需要手动管理队列的头部和尾部位置。以下…...
每日一题34:数据分组之查找每个员工花费的总时间
一、每日一题 表: Employees ------------------- | Column Name | Type | ------------------- | emp_id | int | | event_day | date | | in_time | int | | out_time | int | ------------------- 在 SQL 中,(emp_id, event_day, in_time) 是…...

语言模型解构——Tokenizer
1. 认识Tokenizer 1.1 为什么要有tokenizer? 计算机是无法理解人类语言的,它只会进行0和1的二进制计算。但是呢,大语言模型就是通过二进制计算,让你感觉计算机理解了人类语言。 举个例子:单1,双2&#x…...
前端经验:导出表格为excel并设置样式
应用场景 将网页上的table标签内容导出为excel,并且导出的excel携带样式,比如字色、背景色、对齐等等 实施步骤 必备引入包 npm install xlsx-js-style步骤1:准备好table table可以是已经存在与页面中的,也可以动态创建。 行…...

UFS协议—新手快速入门(二)【5-6】
目录 五、UFS协议栈 六、UFS技术演进与详解 1、UFS应用层 设备管理器 任务管理器 2、UFS传输层 3、UFS互联层 UFS协议—新手快速入门(一)【1-4】 五、UFS协议栈 UFS(Universal Flash Storage)协议是针对固态存储设备&…...

手机建站介绍
随着科技的不断进步和移动互联网的普及,手机应用已经成为人们生活中最不可或缺的一部分。而手机建站作为一种新兴技术,在这一领域也有着广泛的应用。本文将为大家介绍手机建站的概念、优势和应用。 什么是手机建站? 手机建站是指将传统的网络…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...