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

【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录

  • 案例引入
  • 介绍
    • 基本介绍
    • 类图
    • 出场角色
  • 案例实现
    • 案例一
      • 类图
      • 代码实现
    • 案例二
      • 类图
      • 代码实现
  • 外观模式在Mybatis源码中的应用
  • 总结
  • 文章说明

案例引入

在家庭影院中,要享受一场电影,需要如下步骤:

  • 直接用遥控器:统筹各设备开关
  • 开爆米花机
  • 放下屏幕
  • 开投影仪
  • 开音响
  • 开DVD,选dvd
  • 去拿爆米花
  • 调暗灯光
  • 播放
  • 观影结束后,关闭各种设备

【传统方案实现】

创建多个类,分别表示各种机器,然后每个类里面有相应机器的操作方式,最后在主类中分别创建每种机器的对象,并调用其方法来控制机器

在这里插入图片描述

缺点:

  • 如果设备较多,操作流程会比较复杂
  • 在ClientTest 的main方法中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程
  • 不利于在ClientTest 中,去维护对子系统的操作

改进:

  • 定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口提供四个方法ready, play, pause, end),用来访问子系统中的一群接口,也就是说 就是通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心其他子系统的内部细节

介绍

基本介绍

  • 外观模式,也叫“过程模式”
  • 外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得各个子系统更加容易使用
  • 使用外观模式可以为互相关联在一起的错综复杂的类整理出高层接口(API)。其中的Facade角色可以让系统对外只有一个简单的接口(API)。而且,Facade 角色还会考虑到系统内部各个类之间的责任关系和依赖关系,按照正确的顺序调用各个类。定义一个一致的接口,用于屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节

类图

在这里插入图片描述

  • 外观类(Facade):为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象
  • 子系统的集合:指模块或者子系统,处理Facade 对象指派的任务,他是功能的实际提供者。如果有需要,子系统之间可以互相调用
  • 调用者(Client):外观接口的调用者

出场角色

  • Facade(窗口):是代表构成系统的许多其他角色的“简单窗口”。Facade角色向系统外部提供高层接口(API)
  • 构成系统的许多其他角色:这些角色各自完成自己的工作,它们并不知道Facade角色。Facade角色调用其他角色进行工作,但是其他角色不会调用Facade角色
  • Client(请求者):负责调用 Facade角色

在这里插入图片描述

案例实现

案例一

类图

在这里插入图片描述

代码实现

【子系统:DVD机】

package com.atguigu.facade;/*** DVD机*/
public class DVDPlayer {/*** 使用单例模式, 使用饿汉式*/private static DVDPlayer instance = new DVDPlayer();public static DVDPlayer getInstance() {return instance;}/*** 开机*/public void on() {System.out.println(" dvd on ");}/*** 关机*/public void off() {System.out.println(" dvd off ");}/*** 播放*/public void play() {System.out.println(" dvd is playing ");}/*** 暂停*/public void pause() {System.out.println(" dvd pause ..");}
}

【子系统:爆花机】

package com.atguigu.facade;/*** 爆米花机,用于制作爆米花*/
public class Popcorn {private static Popcorn instance = new Popcorn();public static Popcorn getInstance() {return instance;}public void on() {System.out.println(" popcorn on ");}public void off() {System.out.println(" popcorn ff ");}/*** 出爆米花*/public void pop() {System.out.println(" popcorn is poping ");}
}

【子系统:投影仪】

package com.atguigu.facade;/*** 投影仪*/
public class Projector {private static Projector instance = new Projector();public static Projector getInstance() {return instance;}public void on() {System.out.println(" Projector on ");}public void off() {System.out.println(" Projector off ");}/*** 聚焦*/public void focus() {System.out.println(" Projector is Projector  ");}}

【子系统:屏幕】

package com.atguigu.facade;/*** 屏幕*/
public class Screen {private static Screen instance = new Screen();public static Screen getInstance() {return instance;}/*** 屏幕往上升*/public void up() {System.out.println(" Screen up ");}/*** 屏幕下降*/public void down() {System.out.println(" Screen down ");}}

【子系统:立体声】

package com.atguigu.facade;/*** 立体声*/
public class Stereo {private static Stereo instance = new Stereo();public static Stereo getInstance() {return instance;}public void on() {System.out.println(" Stereo on ");}public void off() {System.out.println(" Screen off ");}public void up() {System.out.println(" Screen up.. ");}}

【子系统:灯光】

package com.atguigu.facade;/*** 灯光*/
public class TheaterLight {private static TheaterLight instance = new TheaterLight();public static TheaterLight getInstance() {return instance;}public void on() {System.out.println(" TheaterLight on ");}public void off() {System.out.println(" TheaterLight off ");}/*** 灯光调暗*/public void dim() {System.out.println(" TheaterLight dim.. ");}/*** 灯光调亮*/public void bright() {System.out.println(" TheaterLight bright.. ");}
}

【外观类】

package com.atguigu.facade;/*** 影院外观*/
public class HomeTheaterFacade {//--------------定义各个子系统对象----------------private TheaterLight theaterLight;private Popcorn popcorn;private Stereo stereo;private Projector projector;private Screen screen;private DVDPlayer dVDPlayer;/*** 构造器*/public HomeTheaterFacade() {super();this.theaterLight = TheaterLight.getInstance();this.popcorn = Popcorn.getInstance();this.stereo = Stereo.getInstance();this.projector = Projector.getInstance();this.screen = Screen.getInstance();this.dVDPlayer = DVDPlayer.getInstance();}/*** 操作分成 4 步*/public void ready() {popcorn.on();popcorn.pop();screen.down();projector.on();stereo.on();dVDPlayer.on();theaterLight.dim();}public void play() {dVDPlayer.play();}public void pause() {dVDPlayer.pause();}public void end() {popcorn.off();theaterLight.bright();screen.up();projector.off();stereo.off();dVDPlayer.off();}}

【客户端】

package com.atguigu.facade;public class Client {public static void main(String[] args) {//这里直接调用外观类HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();System.out.println("-------------------------------准备步骤-------------------------------");homeTheaterFacade.ready();System.out.println("-------------------------------电影播放-------------------------------");homeTheaterFacade.play();System.out.println("-------------------------------观看结束-------------------------------");homeTheaterFacade.end();}}

【运行】

-------------------------------准备步骤-------------------------------popcorn on popcorn is poping Screen down Projector on Stereo on dvd on TheaterLight dim.. 
-------------------------------电影播放-------------------------------dvd is playing 
-------------------------------观看结束-------------------------------popcorn ff TheaterLight bright.. Screen up Projector off Screen off dvd off Process finished with exit code 0

案例二

类图

在这里插入图片描述

代码实现

【数据库类】

package com.atguigu.facade.Sample.pagemaker;import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;public class Database {/***防止外部new出Database的实例,所以声明为private方法*/private Database() {}/*** 根据数据库名获取Properties* @param dbname* @return*/public static Properties getProperties(String dbname) { String filename = dbname + ".txt";Properties prop = new Properties();try {prop.load(new FileInputStream(filename));} catch (IOException e) {System.out.println("Warning: " + filename + " is not found.");}return prop;}
}

【数据文件】

hyuki@hyuki.com=Hiroshi Yuki
hanako@hyuki.com=Hanako Sato
tomura@hyuki.com=Tomura
mamoru@hyuki.com=Mamoru Takahashi

【Html文件输出】

package com.atguigu.facade.Sample.pagemaker;import java.io.IOException;
import java.io.Writer;/*** 用于编写简单的Web页面*/
public class HtmlWriter {private Writer writer;public HtmlWriter(Writer writer) {  // 构造函数this.writer = writer;}/*** 输出标题** @param title* @throws IOException*/public void title(String title) throws IOException {writer.write("<html>");writer.write("<head>");writer.write("<title>" + title + "</title>");writer.write("</head>");writer.write("<body>\n");writer.write("<h1>" + title + "</h1>\n");}/*** 输出段落* @param msg* @throws IOException*/public void paragraph(String msg) throws IOException {  writer.write("<p>" + msg + "</p>\n");}/*** 输出超链接* @param href* @param caption* @throws IOException*/public void link(String href, String caption) throws IOException {  paragraph("<a href=\"" + href + "\">" + caption + "</a>");}/*** 输出邮件地址* @param mailaddr* @param username* @throws IOException*/public void mailto(String mailaddr, String username) throws IOException {    link("mailto:" + mailaddr, username);}/*** 结束输出HTML* @throws IOException*/public void close() throws IOException {    writer.write("</body>");writer.write("</html>\n");writer.close();}
} 

【外观类】

package com.atguigu.facade.Sample.pagemaker;import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;public class PageMaker {/*** 防止外部new出PageMaker的实例,所以声明为private方法*/private PageMaker() {}/*** 根据邮件地址和文件名来创建页面* @param mailaddr* @param filename*/public static void makeWelcomePage(String mailaddr, String filename) {try {Properties mailprop = Database.getProperties("maildata");String username = mailprop.getProperty(mailaddr);HtmlWriter writer = new HtmlWriter(new FileWriter(filename));writer.title("Welcome to " + username + "'s page!");writer.paragraph("欢迎来到" + username + "的主页。");writer.paragraph("等着你的邮件哦!");writer.mailto(mailaddr, username);writer.close();System.out.println(filename + " is created for " + mailaddr + " (" + username + ")");} catch (IOException e) {e.printStackTrace();}}
}

【主类】

package com.atguigu.facade.Sample;import com.atguigu.facade.Sample.pagemaker.PageMaker;public class Main {public static void main(String[] args) {PageMaker.makeWelcomePage("hyuki@hyuki.com", "welcome.html");}
}

外观模式在Mybatis源码中的应用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

  • 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
  • 外观模式对客户端与子系统进行解耦,让子系统内部的模块更易维护和扩展
  • 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
  • 当系统需要进行分层设计时,可以考虑使用Facade模式
  • 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口,让新系统与Facade类交互,提高复用性
  • 不能过多的或者不合理的使用外观模式,判断使用外观模式好还是直接调用模块好(如果子系统已经很简洁明了,就不需要使用外观模式了;如果子系统的调用很复杂,就可以使用外观模式)。要以让系统有层次,利于维护为目的
  • 可以递归使用外观模式,比如一开始有几个独立的Facade了,它们分别负责不同的功能,还可以在更外层提取一个Facade来将那几个独立的Facade整合起来

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面

相关文章:

【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入介绍基本介绍类图出场角色 案例实现案例一类图代码实现 案例二类图代码实现 外观模式在Mybatis源码中的应用总结文章说明 案例引入 在家庭影院中&#xff0c;要享受一场电影&#xff0c;需要如下步骤&#xff1a; 直接用遥控器&#xff1a;统筹各设备开关开…...

消息队列 -提供上层服务接口

目录 前言封装数据库封装内存操作内存的设计思想 应答模式 代码实现测试代码 前言 我们之前已经将 数据库 的操作 和文件的操作 都完成了, 但是对于上层调用来说, 并不关心是于数据库中存储数据还是往文件中存储数据, 因此 我们提供一个类, 封装一下 上述俩个类中的操作, 并将…...

maven引入本地jar包的简单方式【IDEA】【SpringBoot】

前言 想必点进来看这篇文章的各位&#xff0c;都是已经习惯了Maven从中央仓库或者阿里仓库直接拉取jar包进行使用。我也是&#x1f921;&#x1f921;。 前两天遇到一个工作场景&#xff0c;对接三方平台&#xff0c;结果对方就是提供的一个jar包下载链接&#xff0c;可给我整…...

【爬虫逆向案例】某易云音乐(评论)js逆向—— params、encSecKey解密

声明&#xff1a;本文只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 【爬虫逆向案例】某易云音乐&#xff08;评论&#xff09;js逆向—— params、encSecKey解密 1、前言2、行动…...

【uni-app】【Android studio】手把手教你运行uniapp项目到Android App

运行到Android App基座 选择运行到Android App基座 选择运行项目 1、连接手机&#xff0c;在手机上选择 传输文件。 2、打开 设置-> 关于本机 -> 版本信息->连续点击4-5次版本号 &#xff0c;输入手机密码&#xff0c;系统就进入了开发者模式。 3、设置 > 其他设…...

多线程(JavaEE初阶系列6)

目录 前言&#xff1a; 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语&#xff1a; 前言&#xff1a; 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下&#xff0c;那么这节中小编将分享一下多线程中的线程池。给大家讲解一…...

shell清理redis模糊匹配的多个key

#!/bin/bash# 定义Redis服务器地址和端口 REDIS_HOST"localhost" REDIS_PORT6380# 获取匹配键的数量 function get_matching_keys() {local key_pattern"$1"redis-cli -h $REDIS_HOST -p $REDIS_PORT -n 0 KEYS "$key_pattern" }# 删除匹配的键 …...

【电网异物检测硕士论文摘抄记录】电力巡检图像中基于深度学习的异物检测方法研究

根据国家电力行业发展报告统计&#xff0c;截止到 2018 年&#xff0c;全国电网 35 千伏及以上的输电线路回路长度达到 189 万千米&#xff0c;220 千伏及以上输电线路回路长度达73 万千米。截止到 2015年&#xff0c;根据国家电网公司的统计 330 千伏及以上输电线路故障跳闸总…...

C++共享数据的保护

虽然数据隐藏保护了数据的安全性&#xff0c;但各种形式的数据共享却又不同程度地破坏了数据的安全。因此&#xff0c;对于既需要共享有需要防止改变的数据应该声明为常量。因为常量在程序运行期间不可改变&#xff0c;所以可以有效保护数据。 1.常对象 常对象&#xff1a;它…...

MyBatisPlus学习记录

MyBatisPlus(简称MP&#xff09;是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提高效率 MyBatisPlus简介 入门案例 创建新模块&#xff0c;选择Spring初始化&#xff0c;并配置模块相关基础信息选择当前模块需要使用的技术集&#xff08;仅选择MySQL …...

如何开启一个java微服务工程

安装idea IDEA常用配置和插件&#xff08;包括导入导出&#xff09; https://blog.csdn.net/qq_38586496/article/details/109382560安装配置maven 导入source创建项目 修改项目编码utf-8 File->Settings->Editor->File Encodings 修改项目的jdk maven import引入…...

libhv之hio_t分析

上一篇文章解析了fd是怎么与io模型关联。其中最主要的角色扮演者&#xff1a;hio_t 1. hio_t与hloop的关系 fd的值即hio_t所在loop ios变量中所在的index值。 hio_t ios[fd] struct hloop_s { ...// ios: with fd as array.index//io_array保存了和hloop关联的所有hio_t&…...

C语言的转义字符

转义字符也叫转移序列&#xff0c;包含如下&#xff1a; 转移序列 \0oo 和 \xhh 是 ASCII 码的特殊表示。 八进制数示例&#xff1a; 代码&#xff1a; #include<stdio.h> int main(void) {char beep\007;printf("%c\n",beep);return 0; }结果&#xff1a; …...

【腾讯云 Cloud Studio 实战训练营】CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手!

CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01; 文章目录 CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01;前言出现的背景一、CloudStudio 是什么&#xff1f;二、CloudStudio 的特点三、CloudS…...

Pandas时序数据分析实践—时序数据集

1. 跑步运动为例&#xff0c;对运动进行时序分析 时序数据是指时间序列数据&#xff0c;是按照时间顺序排列的数据集合&#xff0c;每个数据点都与一个特定的时间戳相关联。在跑步活动中&#xff0c;我们可以将每次跑步的数据记录作为一个时序数据样本&#xff0c;每个样本都包…...

use strict 是什么意思?使用它区别是什么?

use strict 是什么意思&#xff1f;使用它区别是什么&#xff1f; use strict 代表开启严格模式&#xff0c;这种模式下使得 JavaScript 在更严格的条件下运行&#xff0c;实行更严格解析和错误处理。 开启“严格模式”的优点&#xff1a; 消除 JavaScript 语法的一些不合理…...

常见OOM异常分析排查

常见OOM异常分析排查 Java内存溢出Java堆溢出原因解决思路总结 Java内存溢出 java堆用于存储对象实例,如果不断地创建对象,并且保证GC Root到对象之间有可达路径,垃圾回收机制就不会清理这些对象,对象数量达到最大堆的容量限制后就会产生内存溢出异常. Java堆溢出原因 无法在…...

kubernetes网络之网络策略-Network Policies

Kubernetes 中&#xff0c;Network Policy&#xff08;网络策略&#xff09;定义了一组 Pod 是否允许相互通信&#xff0c;或者与网络中的其他端点 endpoint 通信。 NetworkPolicy 对象使用标签选择Pod&#xff0c;并定义规则指定选中的Pod可以执行什么样的网络通信&#xff0…...

交换机VLAN技术和实验(eNSP)

目录 一&#xff0c;交换机的演变 1.1&#xff0c;最小网络单元 1.2&#xff0c;中继器&#xff08;物理层&#xff09; 1.3&#xff0c;集线器&#xff08;物理层&#xff09; 1.4&#xff0c;网桥&#xff08;数据链路层&#xff09; 二&#xff0c;交换机的工作行为 2.…...

8.Winform界面打包成DLL提供给其他的项目使用

背景 希望集成一个Winform的框架&#xff0c;提供权限菜单&#xff0c;根据权限出现各个Winform子系统的菜单界面。不希望把所有的界面都放放在同一个解决方案下面。用各个子系统建立不同的解决方案&#xff0c;建立代码仓库&#xff0c;进行管理。 实现方式 将Winform的UI界…...

海量数据存储组件Hbase

hdfs hbase NoSQL数据库 支持海量数据的增删改查 基于Rowkey查询效率特别高 kudu 介于hdfs和hbase之间 hbase依赖hadoopzookeeper&#xff0c;同时整合框架phoenix(擅长读写),hive&#xff08;分析数据&#xff09; k&#xff0c;v 储存结构 稀疏的&#xff08;为空的不存…...

(一)基于Spring Reactor框架响应式异步编程|道法术器

在执行程序时: 通常为了提供性能,处理器和编译器常常会对指令进行重排序。 从排序分为编译器重排序和处理器重排序两种 * (1)编译器重排序: 编译器保证不改变单线程执行结构的前提下,可以调整多线程语句执行顺序&#xff1b; * (2)处理器重排序&#xff1a; 如果不存在数据依赖…...

Vue3 让localstorage变响应式

Hook使用方式&#xff1a; import {useLocalStore} from "../js/hooks"const aauseLocalStore("aa",1) 需求一&#xff1a; 通过window.localStorage.setItem可以更改本地存储是&#xff0c;还可以更新aa的值 window.localStorage.setItem("aa&quo…...

【深度学习】InST,Inversion-Based Style Transfer with Diffusion Models,论文,风格迁移,实战

代码&#xff1a;https://github.com/zyxElsa/InST 论文&#xff1a;https://arxiv.org/abs/2211.13203 文章目录 AbstractIntroductionRelated WorkImage style transferText-to-image synthesisInversion of diffusion models MethodOverview ExperimentsComparison with Sty…...

【CSS】3D卡片效果

效果 index.html <!DOCTYPE html> <html><head><title> Document </title><link type"text/css" rel"styleSheet" href"index.css" /></head><body><div class"card"><img…...

OrderApplication

目录 1 OrderApplication 2 /// 查询订单 2.1.1 //补充商品单位 2.1.2 //补充门店名称 2.1.3 //补充门店名称 2.1.4 //订单售后 2.1.5 //订单项售后 OrderApplication...

如何在保健品行业运用IPD?

保健品是指能调节机体功能&#xff0c;不以治疗为目的&#xff0c;并且对人体不产生任何急性、亚急性或者慢性危害的产品。保健品是食品的一个种类&#xff0c;具有一般食品的共性&#xff0c;其含有一定量的功效成分&#xff0c;能调节人体的机能&#xff0c;具有特定的功效&a…...

Flink系列之:动态发现新增分区

Flink系列之&#xff1a;动态发现新增分区 一、动态发现新增分区二、Flink SQL动态发现新增分区三、Flink API动态发现新增分区 为了在不重新启动 Flink 作业的情况下处理主题扩展或主题创建等场景&#xff0c;可以将 Kafka 源配置为在提供的主题分区订阅模式下定期发现新分区。…...

eclipse版本与jdk版本对应关系

官网&#xff1a;Eclipse/Installation - Eclipsepedia eclipse历史版本&#xff08;2007-&#xff09;&#xff1a;Older Versions Of Eclipse - Eclipsepedia Eclipse Packaging Project (EPP) Releases | Eclipse Packages...

File类的学习

java.io.File类 文件和目录路径的抽象表达形式是一个与操作系统无关的类&#xff0c;任何一个操作系统都可以使用这个类中的方法 File.pathSeparator 文件路径分隔符&#xff0c;windows是分号&#xff0c;linux是&#xff1a; File.separator 文件名分隔符&#xff0c;window…...