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

设计模式(十):结构型之外观模式

设计模式系列文章

设计模式(一):创建型之单例模式

设计模式(二、三):创建型之工厂方法和抽象工厂模式

设计模式(四):创建型之原型模式

设计模式(五):创建型之建造者模式

设计模式(六):结构型之代理模式

设计模式(七):结构型之适配器模式

设计模式(八):结构型之装饰器模式

设计模式(九):结构型之桥接模式

设计模式(十):结构型之外观模式


目录

  • 一、设计模式分类
  • 二、外观模式
    • 1、概述
    • 2、结构
    • 3、实现
    • 4、使用场景
    • 5、源码解析


一、设计模式分类

  • 创建型模式
    • 用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”
    • 提供了单例、原型、工厂方法、抽象工厂、建造者 5 种创建型模式
  • 结构型模式
    • 用于描述如何将类或对象按某种布局组成更大的结构
    • 提供了代理、适配器、桥接、装饰、外观、享元、组合 7 种结构型模式
  • 行为型模式
    • 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责
    • 提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器 11 种行为型模式

二、外观模式

1、概述

定义

  • 又名门面模式
    • 是一种通过为多个复杂的子系统提供一个一致的接口
    • 而使这些子系统更加容易被访问的模式
  • 该模式对外有一个统一接口
  • 外部应用程序不用关心内部子系统的具体的细节
  • 这样会大大降低应用程序的复杂度,提高了程序的可维护性

在这里插入图片描述

2、结构

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

  • 外观(Facade)角色:为多个子系统对外提供一个共同的接口
  • 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它

3、实现

智能家电控制

  • 一个人在家生活:每次都需要打开灯、打开电视、打开空调
  • 睡觉时关闭灯、关闭电视、关闭空调;操作起来都比较麻烦
  • 买了智能音箱,可以通过语音直接控制这些智能家电的开启和关闭

类图如下:

在这里插入图片描述

代码如下:

  • 家电类
//灯类
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() {light = new Light();tv = new TV();airCondition = new AirCondition();}//通过语言控制public void say(String message) {if(message.contains("打开")) {on();} else if(message.contains("关闭")) {off();} else {System.out.println("我还听不懂你说的!!!");}}//一键打开功能private void on() {light.on();tv.on();airCondition.on();}//一键关闭功能private void off() {light.off();tv.off();airCondition.off();}
}
  • 客户端测试类
public class Client {public static void main(String[] args) {//创建外观对象SmartAppliancesFacade facade = new SmartAppliancesFacade();//客户端直接与外观对象进行交互facade.say("打开家电");System.out.println("==================");facade.say("关闭家电");}
}结果:
打开电灯。。。。
打开电视机。。。。
打开空调。。。。
==================
关闭电灯。。。。
关闭电视机。。。。
关闭空调。。。。

好处

  • 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类
  • 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易

缺点

  • 不符合开闭原则,修改很麻烦

4、使用场景

  • 对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系
  • 当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问
  • 当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性

5、源码解析

  • 使用tomcat作为web容器时,接收浏览器发送过来的请求,tomcat会将请求信息封装成ServletRequest对象
  • ServletRequest是一个接口,它还有一个子接口HttpServletRequest
  • request对象肯定是一个HttpServletRequest对象的子实现类对象,到底是哪个类的对象呢?
  • 通过输出request对象,我们就会发现是一个名为RequestFacade的类的对象

在这里插入图片描述

  • RequestFacade类就使用了外观模式

结构图:

在这里插入图片描述

RequestFacade类:

public class RequestFacade implements HttpServletRequest {protected Request request = null;public RequestFacade(Request request) {this.request = request;}...public Object getAttribute(String name) {if (this.request == null) {throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));} else {return this.request.getAttribute(name);}}public Enumeration<String> getAttributeNames() {if (this.request == null) {throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));} else {return Globals.IS_SECURITY_ENABLED ? (Enumeration)AccessController.doPrivileged(new GetAttributePrivilegedAction()) : this.request.getAttributeNames();}}public String getCharacterEncoding() {if (this.request == null) {throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));} else {return Globals.IS_SECURITY_ENABLED ? (String)AccessController.doPrivileged(new GetCharacterEncodingPrivilegedAction()) : this.request.getCharacterEncoding();}}...}

为什么在此处使用外观模式呢?

  • 定义 RequestFacade 类,分别实现 ServletRequest
  • 同时定义私有成员变量 Request ,并且方法的实现调用 Request 的实现
  • 将 RequestFacade上转为 ServletRequest 传给 servlet 的 service 方法
  • 这样即使在 servlet 中被下转为 RequestFacade ,也不能访问私有成员变量对象中的方法
  • 既用了 Request ,又能防止其中方法被不合理的访问

相关文章:

设计模式(十):结构型之外观模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…...

买法拍房需要注意什么

法拍房&#xff0c;由于其价格亲民、房屋信息透明度高、竞拍过程公平公正而受到越来越多的人开始关注。但是其中又有着许多的风险及相关的注意事项。那么&#xff0c;如何做到成功“捡漏”&#xff0c;买法拍房需要注意什么呢? 买法拍房需要注意什么 1、隐藏的各种收费 税费&a…...

linux命令输出结果但不显示在屏幕上的通用办法

linux命令输出结果但不显示在屏幕上的通用办法 这个针对于我这种小白马大哈很简单的一个命令&#xff0c;记给自己备用 举个例子&#xff1a;unzip命令不输出结果 unzip xx.zip > /dev/null 2>&1 unzip xx.zip > /dev/null 前半部分是将标准输出重定向到空设备&a…...

【Linux系统进阶详解】Linux字符权限rwx-权限组合原理,对应类型ugo,user,group,other,+-=详解及权限管理实战

在Linux系统中,每个文件和目录都有三种权限:读权限(r)、写权限(w)和执行权限(x)。这些权限可以被分配给三个不同的用户组:用户(user)、组(group)和其他人(other)。此外,权限可以使用“+”、“-”和“=”符号进行修改。 权限组合原理 Linux系统中的权限由字母…...

凡人修C传——专栏从凡人到成仙系列目录

这里先感谢博主THUNDER王给我提出来的一个创作建议&#xff0c;让我有了创作的灵感来创建这一篇博客以及凡人修C传这一个系列的文章。 本文最主要的目的就是给大家一个凡人修C传的一个目录&#xff0c;让大家更加容易学到自己想学的地方。 &#x1f4dd;【个人主页】&#xff1…...

隐藏python代码,售卖并保护源代码

我写了一个基于pytorch框架的特殊卷积&#xff0c;他的使用方式和其他的卷积一样&#xff0c;但是我想把它卖出去&#xff0c;希望隐藏特殊卷积的代码 1、如果您希望隐藏特殊卷积的代码并将其作为一个可售卖的产品&#xff0c;可以考虑以下几种方法来保护您的代码&#xff1a;…...

Material—— VAT(Houdini To UE)

目录 一&#xff0c;介绍 二&#xff0c;柔体 二&#xff0c;刚体 一&#xff0c;介绍 VAT是将动画数据存储在纹理中&#xff0c;通过GPU运算来实现动画的技术&#xff1b;VAT纹理包含每个顶点在不同帧的位置信息&#xff0c;而每个像素代表一个顶点在某个时间点的位置&…...

视频后期剪辑

文章目录 后期剪辑软件三方插件提供动画制作软件 后期剪辑软件 视频剪辑后期处理涉及到多个软件和插件&#xff0c;下面是对其中几个主要软件及其相关插件的扩展介绍&#xff0c;以及为它们提供插件的一些知名第三方公司。 Adobe After Effects&#xff1a; Adobe After Effec…...

Python3+Selenium2完整的自动化测试实现之旅(七):完整的轻量级自动化框架实现

一、前言 前面系列Python3Selenium2自动化系列博文&#xff0c;陆陆续续总结了自动化环境最基础环境的搭建、IE和Chrome浏览器驱动配置、selenium下的webdriver模块提供的元素定位和操作鼠标、键盘、警示框、浏览器cookie、多窗口切换等场景的方法、web自动化测试框架、python面…...

泰山信息科技5周年:无尽的感恩,非常非常的惋惜

去年的时候&#xff0c;庆贺4周年&#xff0c;公司员工一起去某个地方玩&#xff08;确实没吃到什么东西&#xff09;。这是当时的情形&#xff1a; 因为各种原因&#xff0c;今年3月无锡研发基地解散。作为技术总监&#xff0c;我是非常非常的惋惜。因为我真的想把泰山OFFICE做…...

LabVIEW编程开发PCB测试仪

LabVIEW编程开发PCB测试仪 使用PXI和LabVIEW的PCB钉床测试仪 用于PCB&#xff08;印刷电路板&#xff09;的钉床测试仪&#xff0c;使用PXI和LabVIEW。一家电子制造公司需要测试仪来测试他们的PCB产品。钉床测试仪是一种具有连接到电路板上各个测试点的引脚的测试。电路板需要…...

React使用Electron开发桌面端

React是一个流行的JavaScript库&#xff0c;用于构建Web应用程序。结合Electron框架&#xff0c;可以轻松地将React应用程序打包为桌面应用程序。以下是使用React和Electron开发桌面应用程序的步骤&#xff1a; 1. 安装Electron 首先&#xff0c;你需要安装Electron。在终端中…...

springboot+vue餐厅点餐系统在线点餐系统(含源码+数据库)

1.系统分析 系统用例图如下所示。 从用户、餐厅等方面进行需求分析如下。 1.用户需求&#xff1a;系统应该提供简单易用的用户界面&#xff0c;用户可以浏览餐厅菜单&#xff0c;选择菜品&#xff0c;下订单。此外&#xff0c;应该允许用户管理个人信息和查看历史订单。 2.餐…...

Vue.js 中的 TypeScript 支持是什么?如何使用 TypeScript?

Vue.js 中的 TypeScript 支持 Vue.js 是一款流行的前端框架&#xff0c;它提供了一种简单、灵活的方式来构建用户界面。随着 TypeScript 的普及&#xff0c;Vue.js 也开始支持 TypeScript&#xff0c;使得开发者可以使用类型检查等 TypeScript 特性来提高代码质量和可维护性。…...

测试者必知—如何做Web测试?常见测试点总结

目录 前言&#xff1a; 一、Web应用程序 二、功能测试 三、易用性测试&#xff08;界面测试&#xff09; 四、兼容性测试 五、安全性测试 六、性能测试 前言&#xff1a; Web测试是指对基于Web技术的应用程序进行测试&#xff0c;以测试其功能、性能、安全和稳定性等方面的表…...

怎么转换英文音频成文字?英文音频转文字app分享

两位朋友正在讨论如何将一段英文讲座的音频转换成文字&#xff0c;以便于学习和理解。 Sophia&#xff1a;嗨&#xff0c;我最近听了一段非常精彩的英文讲座&#xff0c;但是对于我来说&#xff0c;理解听到的内容有些困难。你知道有什么方法可以将英文音频转换成文字吗&#…...

esp32-cam拍照上传,app inventor 制作安卓app实时显示

1、ESP32-cam开发环境配置 本例程 是利用arduino IDE开发,关于arduino IDE 的esp32环境配置可参考:环境配置: 点击跳转 安装好esp32 环境,开发板选择esp32 wrover module开发板,其他默认即可。 2 、程序下载 示例程序下载:点击下载 需要修改的信息有WIF名称,WIFI密码,…...

基于jsp+mysql+Spring+mybatis+Springboot的Springboot实现的就业信息管理平台

运行环境: 最好是java jdk 1.8&#xff0c;我在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以&#xff0c;如果编译器的版本太低&#xff0c;需要升级下编译器&#xff0c;不要弄太低的版本 tomcat服务器环…...

阿里巴巴内部10w字Java面试小抄火了,完整版开放下载

Java 面试 “金九银十”这个字眼对于程序员应该是再熟悉不过的了&#xff0c;每年的金九银十都会有很多程序员找工作、跳槽等一系列的安排。说实话&#xff0c;面试中 7 分靠能力&#xff0c;3 分靠技能&#xff1b;在刚开始的时候介绍项目都是技能中的重中之重&#xff0c;它…...

Logback自定义DBAppender保存系统日志到数据库

在系统中采用了spring boot logback&#xff0b;slf4j的日志框架&#xff0c;将系统日志记录到数据库。 相关参考来源&#xff1a; 官方文档-DBAppender Logback输出日志到自定义MySQL数据库&#xff08;重写DBAppender&#xff09; logback日志框架中filter的使用 1. 添加依…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...