【设计模式】深入浅出--外观模式

news2025/1/14 18:29:33

文章目录

  • 前言
  • 一、外观模式介绍
  • 二、案例场景
  • 三、外观模式优缺点
  • 四、外观模式应用场景
  • 总结

前言

不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶、茶具和开水,而去茶馆喝茶,最简单的方式就是跟茶馆服务员说想要一杯什么样的茶,是铁观音、碧螺春还是西湖龙井?正因为茶馆有服务员,顾客无须直接和茶叶、茶具、开水等交互,整个泡茶过程由服务员来完成,顾客只需与服务员交互即可,整个过程非常简单省事。

以上这种场景类似设计模式中的外观模式,也叫做门面模式

外观模式通过引入一个新的外观类来实现该功能,外观类充当了“服务员”的角色,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。

本文我们一起来聊聊外观模式。

一、外观模式介绍

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互为复杂的子系统调用提供一个统一的入口降低子系统与客户端的耦合度,且客户端调用非常方便

外观模式结构图:
在这里插入图片描述

  • Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。
  • SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

二、案例场景

  • 场景一:自己泡茶,整个过程应该是“烧开水->拿茶具->泡茶叶”然后喝茶。

    定义一个饮用水类:DrinkableWater

    /**
     * 烧水
     */
    public class DrinkableWater {
    
        public DrinkableWater(){
            System.out.println("水准备好了");
        }
    
        //烧水
        public void facadeWater(){
            System.out.println("水烧开了");
        }
    }
    

    定义一个茶叶类:Tea

    /**
     * 茶叶
     */
    public class Tea {
    
        public Tea(){
            System.out.println("茶叶准备好了");
        }
    
        //取茶
        public void facadeTea(){
            System.out.println("可以泡茶了");
        }
    }
    

    定义一个茶杯类:TeaCup

    /**
     * 茶杯
     */
    public class TeaCup {
    
        public TeaCup(){
            System.out.println("茶杯准备好了");
        }
    
        //泡茶
        public void facadeTeaCup(Tea tea){
            tea.facadeTea();
            System.out.println("茶叶泡进茶杯了");
            System.out.println("茶冲好了");
        }
    }
    

    准备就绪,开始泡茶

    public static void main(String[] args) {
        System.out.println("准备泡茶...");
        DrinkableWater drinkableWater = new DrinkableWater();
        TeaCup teaCup = new TeaCup();
        Tea tea = new Tea();
    
        drinkableWater.facadeWater();
        teaCup.facadeTeaCup(tea);
        System.out.println("喝茶...");
    }
    

    运行结果

    准备泡茶...
    水准备好了
    茶杯准备好了
    茶叶准备好了
    水烧开了
    可以泡茶了
    茶叶泡进茶杯了
    茶冲好了
    喝茶...
    
  • 场景二:去茶馆喝茶,不用自己动手泡茶了,直接告诉茶馆的服务员就行了。

    定义一个服务员类:

    /**
     * 服务员
     */
    public class Waiter {
    
        private DrinkableWater drinkableWater = new DrinkableWater();
        private TeaCup teaCup = new TeaCup();
        private Tea tea = new Tea();
    
        //获得一杯茶
        public void getTea(){
            drinkableWater.facadeWater();
            teaCup.facadeTeaCup(tea);
        }
    }
    

    客户类:Customer

    public class Customer {
    
        public static void main(String[] args) {
            //叫店小二
            Waiter waiter = new Waiter();
            //从店小二那获得一杯茶
            waiter.getTea();
        }
    }
    

    运行结果

    水准备好了
    茶杯准备好了
    茶叶准备好了
    水烧开了
    可以泡茶了
    茶叶泡进茶杯了
    茶冲好了
    

在上面的泡茶的例子中,客人就是客户角色,茶馆服务员就是门面角色,茶具、饮用水、茶叶就是子系统角色。

代码看上去都很简单,也许你感觉二者区别不是很大,假如在软件开发中三个子系统之间有先后顺序,还有来自不同网络开销,我们通过门面模式提供的方法,就屏蔽了这些差异,让我们只需要调用门面角色提供给我们的方法即可

三、外观模式优缺点

  • 优点
    • 减少系统的相互依赖
      如果我们不使用门面模式, 外界访问直接深入到子系统内部, 相互之间是一种强耦合关系, 你死我就死, 你活我才能活, 这样的强依赖是系统设计所不能接受的, 门面模式的出现就很好地解决了该问题, 所有的依赖都是对门面对象的依赖, 与子系统无关。
    • 提高安全性
      想让你访问子系统的哪些业务就开通哪些逻辑, 不在门面上开通的方法, 你休想访问到。
  • 缺点
    • 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。
    • 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。

四、外观模式应用场景

  1. 解决易用性问题
    门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。
  2. 解决性能问题
    通过将多个接口调用替换为一个门面接口调用,减少网络通信成本,提高客户端的响应速度。
  3. 解决分布式事务问题
    需要调用多个子系统的接口方法,而这些接口要么都成功,要么都失败,我们就可以利用门面模式包裹这些子系统接口,然后通过某种方法保证这些接口在一个事务中完成。

总结

  • 在几乎所有的软件中都能够找到外观模式的应用,如绝大多数B/S系统都有一个首页或者导航页面,大部分C/S系统都提供了菜单或者工具栏,在这里,首页和导航页面就是B/S系统的外观角色,而菜单和工具栏就是C/S系统的外观角色,通过它们用户可以快速访问子系统,降低了系统的复杂程度。所有涉及到与多个业务对象交互的场景都可以考虑使用外观模式进行重构。

  • 很多时候不是设计模式没有用,而是自己编程开发经验不足导致即使学了设计模式也很难驾驭。

  • 毕竟这些知识都是经过一些实际操作提炼出来的精华。

希望对你有帮助,如有问题欢迎评论区讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高效的配置文件读取工具支持properties和yaml

JefConfig 前言 日常工作中不知道到大家有没有遇到以下几种情况: 1、在程序启动时需要加载配置文件,但是发现程序只能从固定位置读取配置文件。 2、程序在集成了spring框架后,想从配置文件中获取某个配置,但是发现当前程序并未交…

并查集原理及代码实现

并查集 首先要明确的是并查集是森林。由多棵树组成。 并查集 (英文:Disjoint-set data structure,直译为不交集数据结构),用于处理一些 不交集 (Disjoint sets,一系列没有重复元素的集合&…

android framework-SystemServer进程

SystemServer进程信息 一、SystemServer整体时序图 涉及源码路径: android-10.0.0_r41\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java android-10.0.0_r41\frameworks\base\core\java\com\android\internal\os\Zygote.java android-10.0.0_r4…

JAVAWeb07-WEB 开发通信协议-HTTP 协议-关联篇

1. 概述 1.1 官方文档及示例说明 1.1.1 请求头 1.1.2 响应头 1.1.3 HTTP 响应状态码 HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头&a…

leetcode 1372. Longest ZigZag Path in a Binary Tree(二叉树中最长的之字形路径)

找出最长的之字型路径长度。 可以选择从二叉树的任意一个节点出发。 路径长度为路径中的节点数-1. 思路: 符合DFS的特征。 方向是左右交替的,可以定义0,1两个方向。 如果当前方向是左,下一方向就是右,反之亦然。每次…

FinClip|小程序云开发的那点事儿

在开发一个小程序时,除了考虑界面功能逻辑外,还需要后端的数据支持,开发者需要提前考虑服务器、存储和数据库等相关需求的支持能力,此外还可能需要花费时间精力在部署应用、和依赖服务的建设上。 因此,微信小程序为了…

dolphinscheduler3.1.3版本代码编译运行方法

说明 该文档适用于dolphinscheduler 3.1.3-release版本。 一 环境准备 需要使用的环境包括JDK1.8,以及Maven 3.6以上的版本,这里使用低于3.6版本的Maven也可以调试运行,不过在打包的时候会有报错,最好使用高版本的maven。 二 …

数字IC笔试面试常考问题及答案汇总(内含各岗位大厂题目)

经历了无数的笔试面试之后,不知道大家有没有发现数字IC的笔试面试还是有很多共通之处和规律可循的。所以一定要掌握笔试面试常考的问题。 数字IC笔试面试常考问题及答案汇总(文末可领全部哦~) 验证方向(部分题目) Q1…

android studio APP工程的项目结构说明及创建

目录 1.APP工程的项目结构图 2.功能说明 2.1app 2.2Gradle Scripts 3.创建新的APP页面 补充: 1.APP工程的项目结构图 2.功能说明 该项目下两个分类:一个是app(代表app模块);另一个是Gradle Scripts。 2.1app app下面有3个…

虚拟机安装Centos7,ping不通百度

虚拟机安装Centos7,ping不通百度 一、虚拟机网络配置 网络适配器选择桥接模式,不勾选复制物理网络连接状态。 同时虚拟机使用默认配置都是桥接。 二、配置静态IP 1、首先,查看宿主机的IP和网关 2、配置静态ip的文件地址及修改命令如下&…

mybatis分页插件的基本理解和使用

mybatis分页插件的基本理解和使用 为什么要使用mybatis分页插件? 分页是一种将所有数据分段展示给用户的技术。用户每次看到的不是全部数据,而是其中一部分,如果在其中没有找到自己想要的内容,用户可以通过制定页码或者是翻页的…

就业并想要长期发展选数字后端还是ic验证?

“就业并想要长期发展选数字后端还是ic验证?” 这是知乎上的一个热点问题,浏览量达到了13,183。看来有不少同学对这个问题感到疑惑。之前更新了数字后端&数字验证的诸多文章,从学习到职业发展,都写过,唯一没有做过…

CRM系统能帮助企业解决哪些问题?

随着信息化技术的不断发展和全球化的推进,市场竞争越来越激烈,客户需求也在不断变化。为了应对这种情况,越来越多的企业开始使用CRM系统来管理与客户的关系。那么,CRM系统到底解决了企业哪些问题呢? 一、提高客户满意…

亿发软件:传统食品饮料批发行业如何通过信息化管理系统降本增效?

传统食品饮料批发行业信息化水平较低,存在多重管理难题,例如: 手动数据输入和管理,导致错误和效率低下; 数据缺乏实时可见性,无法实时了解企业仓库存量、销售额和其他关键业务指标; 低效的供应链…

【Android】之【常用布局】

一、简介 Android常用布局分别是 1、线性布局LinearLayout 2、相对布局RelativeLayout 3、绝对布局AbsoluteLayout 4、帧布局FrameLayout 5、表格布局TableLayout 6、网格布局GridLayout 7、约束布局ConstraintLayout 二、详解 2.1. LinearLayout (线性布局) 线性布局是一种非…

Rabbit与springboot整合-1

目录 1、整体结构 2、pom引入 3、配置文件 4、代码 公共类 controller类 JSON转换类 监听-接收发送消息类 1、整体结构 2、pom引入 <!--rabbitmq--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st…

C++引用与引用两大应用场景,临时变量的常性,常引用与权限大小问题

tips 内存栈区的用习惯是先使用高地址&#xff0c;然后使用低地址嘛顺序表数组支持随机下标访问&#xff0c;也是目前已知的仅有的数据结构类当中的话&#xff0c;它不可以不仅可以去定义变量&#xff0c;它也可以定义函数&#xff0c;这个跟c当中的结构体不一样的&#xff0c…

数据结构考研版——队列的配置问题

一、正常配置下的情况 队空状态 frontrear;入队操作 出队操作 队满状态 在正常配置下元素的个数&#xff08;rear>front&#xff09; 当rear<front 综上所述用一个表达式表示&#xff1a;(rear-frontmaxSize)%maxSize 二、非正常配置下的情况1 队空状态 入队操作…

Stable Diffusion-webUI ckpt模型、lora模型的区别和使用

一、常用的两种模型&#xff1a;ckpt和Lora分别是什么&#xff1f;有什么区别&#xff1f; 1、CKPT&#xff08;CheckPoint&#xff09; 经过训练的图片合集&#xff0c;被称作模型&#xff0c;也就是chekpoint&#xff0c;体积较大&#xff0c;一般真人版的单个模型的大小在…

StarRC的妙用

在整个R2G的流程里边&#xff0c;寄生参数抽取&#xff08;StarRC&#xff09;是比较没有存在感的。大部分的时间&#xff0c;工程师们只是用这个工具来刷SPEF。并不会关注太多。这本身其实是一个好事情&#xff0c;反向证明了参数抽取工具的高度稳定性&#xff01; 但是&#…