C# 设计模式之外观模式

news2024/12/29 11:18:40

总目录


前言

在软件开发过程中,要完成一个功能,可能需要调用很多接口,不仅增加了代码间的耦合度,也增加了调试成本和维护的复杂度。不如我们把这些接口再封装一次,给一个很好的“外观”,让使用者使用更方便,只需调用一个接口,就可以完成以前调用多个接口的来完成任务,相信大家对这种编码技巧并不陌生,这就是本文将介绍的外观模式。


1 基础介绍

  1. 外观模式(Facade Pattern)也被称为 门面模式

  2. 来个图,直观的了解下
    在这里插入图片描述
    原本客户端需要直接调用多个不同子系统的接口,调用关系混乱,代码耦合度高,使用了外观模式后,所有的客户端只需和子系统的 门面 facade 打交道,子系统也只需和facade打交道,不仅捋顺了各个系统之间的关系,也减低了代码间的耦合度。

  3. 定义:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

  4. 使用外观模式时,我们创建了一个统一的类,用来包装子系统中一个或多个复杂的类,客户端可以直接通过外观类来调用内部子系统中方法,从而外观模式让客户和子系统之间避免了紧耦合。

  5. 外观模式包含如下两个角色:

    • 外观角色(Facade):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。

    • 子系统角色(SubSystem):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

  6. 使用分析:

    • 一个系统可以有多个门面类
      在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。当然这并不意味着在整个系统里只有一个门面类,而仅仅是说对每一个子系统只有一个门面类。或者说,如果一个系统有好几个子系统的话,每一个子系统都有一个门面类,整个系统可以有数个门面类。

    • 为子系统增加新行为
      初学者往往以为通过继承一个门面类便可在子系统中加入新的行为,这是错误的。门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。比如医院中的接待员并不是医护人员,接待员并不能为病人提供医疗服务。

    • Facade有助于建立层次结构的系统,实现了子系统与客户之间的松耦合关系,子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。Facade消除了复杂的循环依赖关系。这一点在客户程序与子系统分别实现的时候格外重要。

    • 从客户程序的角度来看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。

2 使用场景

  • 适用于一些有多个子系统,需要为这些复杂的系统提供一个统一接口的软件系统
  • 适用于存在多个子系统且需要保持子系统的独立性的时候
  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口。其中三层架构就是这样的一个例子。

3 实现方式

以我们乘坐高铁为例,一般我们必须做以下步骤:

  • 购买高铁票
  • 过安检
  • 过检票口,进入高铁站,从站内乘坐高铁

1 当我们不使用外观模式的时候

    //车票子系统
    public class TicketsSys
    {
        //售票方法
        public void SaleTicket()
        {
            Console.WriteLine("售票系统 - 已售出高铁票一张");
        }
    }

    //安检系统
    public class SecurityCheckSys
    {
        //安检方法
        public void SecurityCheck()
        {
            Console.WriteLine("安检系统 - 已完成安检");
        }
    }

    //检票系统
    public class TicketCheckSys
    {
        public void TicketCheck()
        {
            Console.WriteLine("检票系统 - 已完成检票");
        }
    }

客户端调用各个子系统,实现乘坐高铁

        static void Main(string[] args)
        {
            //1 先购买高铁票
            TicketsSys ticketsSys = new TicketsSys();
            ticketsSys.SaleTicket();

            //2 再进行安检
            SecurityCheckSys securityCheckSys = new SecurityCheckSys();
            securityCheckSys.SecurityCheck();

            //3 再检票
            TicketCheckSys ticketCheckSys = new TicketCheckSys();
            ticketCheckSys.TicketCheck();

            //4 最后 乘坐高铁
            Console.WriteLine("欢迎乘坐高铁,祝您旅途愉快!");

            Console.ReadKey();
        }

在上面的额案例中,客户端必须同时保存售票系统,安检系统,检票系统的引用,如果这些子系统发生改变时,此时客户端的调用代码也要随之改变,这样就没有很好的可扩展性。那我们看看外观模式是如何解决这个问题的。

2 使用外观模式时

	// 外观类 或 门面类
    //外观模式的核心类
    public class FacadeSys
    {
        private TicketsSys ticketsSys;
        private SecurityCheckSys securityCheckSys;
        private TicketCheckSys ticketCheckSys;

        public FacadeSys()
        {
            this.ticketsSys = new TicketsSys();
            this.securityCheckSys = new SecurityCheckSys();
            this.ticketCheckSys = new TicketCheckSys();
        }

        //乘坐高铁
        public void TakeHighspeedRail()
        {
            //1 先购买高铁票
            ticketsSys.SaleTicket();

            //2 再进行安检
            securityCheckSys.SecurityCheck();

            //3 再检票
            ticketCheckSys.TicketCheck();

            //4 最后 乘坐高铁
            Console.WriteLine("欢迎乘坐高铁,祝您旅途愉快!");
        }
    }


    //车票子系统
    public class TicketsSys
    {
        //售票方法
        public void SaleTicket()
        {
            Console.WriteLine("售票系统 - 已售出高铁票一张");
        }
    }

    //安检系统
    public class SecurityCheckSys
    {
        //安检方法
        public void SecurityCheck()
        {
            Console.WriteLine("安检系统 - 已完成安检");
        }
    }

    //检票系统
    public class TicketCheckSys
    {
        public void TicketCheck()
        {
            Console.WriteLine("检票系统 - 已完成检票");
        }
    }

客户端调用,实现乘坐高铁

        static void Main(string[] args)
        {
            FacadeSys facadeSys = new FacadeSys();
            facadeSys.TakeHighspeedRail();

            Console.ReadKey();
        }

使用了外观模式之后,客户端只依赖与外观类,从而将客户端与子系统的依赖解耦了,如果子系统发生改变,此时客户端的代码并不需要去改变。外观模式的实现核心主要是:由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。

外观模式的实现方式和适配器模式非常类似,然而外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口包装获得适配,而外观模式是提供一个统一的接口来简化接口。

4 优缺点分析

  • 优点

    • 外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单。
    • 外观模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件是紧耦合的。松耦合使得子系统的组件变化不会影响到它的客户。
  • 缺点

    • 如果增加新的子系统可能需要修改外观类或客户端的源代码,这样就违背了”开——闭原则“(不过这点也是不可避免)。

结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
C#设计模式之十外观模式(Facade Pattern)【结构型】
C#设计模式(11)——外观模式(Facade Pattern)

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

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

相关文章

14. 计算机网络HTTPS协议(二)

1. 前言 上一章节中我们主要就 HTTPS 协议的前置知识进行介绍,下面会继续介绍 HTTPS 的通信过程以及抛出一些常见问题的探讨。因为候选人准备面试的时间和精力是比较有限的,我们在学习的过程要抓住重点,如果感觉对于细节缺乏了解,可以通过维基百科和查阅 StackOverflow 等…

美国大语言模型军事应用典型案例

源自:北京科技大学机械工程学院 作者:陈哲涵 黎学臻 注:若出现无法显示完全的情况,可 V 搜索“人工智能技术与咨询”查看完整文章 人工智能、大数据、多模态大模型、计算机视觉、自然语言处理、数字孪生、深度强化学习 课程也可…

AbMole革命性发现:CUDC-907——单一分子双重抑制PI3K与HDAC的创新突破

在生物医学研究的浩瀚宇宙中,科学家们不断探索着新的方法来对抗复杂的疾病机制。今天,我们要探讨的是一项令人瞩目的研究成果——CUDC-907,这一创新分子在抑制PI3K(磷脂酰肌醇3-激酶)和HDAC(组蛋白去乙酰化…

c++——map、set底层之AVL树(动图演示旋转)

在上一篇博客里面我们提到了set和map的使用;这篇博客重点介绍他们的底层逻辑 c之set和map——关联容器(非顺序容器——list、vector) 目录 文章目录 前言 一、底层结构 二、AVL 树 1.AVL树的概念 2.AVL树节点的定义 3、AVL树的插入 三、 AVL树…

Databend 开源周报第 156 期

Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend。 支持 Share Cata…

深入解读 Scrapy 框架原理与源码

🛠️ Scrapy 框架原理解读 Scrapy 是一个强大的 Python 爬虫框架,其设计理念基于事件驱动的异步编程,通过高度模块化的方式实现爬虫功能。Scrapy 框架的核心组成包括爬虫(Spider)、调度器(Scheduler&#…

大模型书籍推荐:《大规模语言模型:从理论到实践》

书籍简介 在当前的人工智能领域,大规模语言模型(Large Language Models, LLMs)无疑是最重要的研究方向之一。它们不仅在自然语言处理方面取得了显著成果,还为其他领域带来了革命性的变化。《大规模语言模型:从理论到实…

维语驾考这款软件有人用过吗?靠谱吗?

维语驾考是专门为维吾尔语学车考驾照的学员而准备的驾考刷题软件。书写延续维语用法自右向左书写,可调节字号大小,支持维汉双语切换。2024驾考新规题库,内含科目一、科目四全真题库,每道题配备详细解析,帮助学员理解透…

Openwrt配置ZeroTier,实现公网访问内网中服务器

ZeroTier注册&Openwrt初始配置 首先来到Openwrt的VPN→ZeroTier页面,进行一个很简单的注册 注册后去zerotier的网页管理页面进行一个很简单的创建网络 复制网络ID备用 在openwrt填写网络ID并启用。如果你需要访问内网主机勾上 自动客户端NAT 在zerotier网络管理…

电子合同签署:2024年十佳选择与评估

文章将介绍10款电子合同签署平台:e签宝、上上签、合同宝、腾讯电子签、合易签、Zoho Sign、Nitro Sign、Secured Signing、Signeasy、Lightico。 在当今快速发展的商业环境中,选择一款合适的电子合同签署平台对于保证工作效率和合同执行的安全性至关重要…

精准洞察农田生态,智慧农业物联网环境监测与数据采集系统来袭

随着智慧农业的快速发展,利用物联网技术实现对农田种植状态的精准监测变得愈发重要。为了确保监测的准确性、一致性和有效性,规范农田物联网监测设备的技术参数、部署安装以及数据对接等技术指标势在必行。 本文技术说明旨在为相关设备的选择、安装和集…

深入源码P3C-PMD:rule (4)

系列文章目录 文章目录 系列文章目录rule 的应用类别 rule rule 自定义XML rule 定义Tree 漫游错误报告生命周期 designer rule相关的代码在每个子 module 的 rule 文件夹。而且也以一些 ruleset 为范围分了文件夹,如下图所示: 对每个 rule 来说&#xf…

Model Counting 2024 Public Instance Track 1 18000s(5h)测试结果

测试求解器:SharpSAT-TD与SharpSATTD-CH 18000s测试结果 测试结果图 对3600s未得到结果的数据进行18000s的测试,48组数据,最终有4组在18000s(5h)内解出 测试数据117 SharpSAT-TD输出: SharpSATTD-CH输出…

2024年底前,河南建筑装饰企业资质延期资料准备要点

针对2024年底前河南建筑装饰企业资质延期的资料准备要点,结合当前的政策要求和实际情况,以下是一些关键的准备要点: 一、了解政策与要求 政策关注: 密切关注河南省住房和城乡建设厅及地方建设主管部门发布的最新政策文件、通知公…

万字长文带你入门shell编程(超详细)

一、概述 Shell 是计算机操作系统中用户与操作系统内核之间的接口层,它提供了一种方式让用户能够通过命令行界面(CLI)与操作系统交互。Shell 可以被视为一个命令解释器,它接收用户输入的命令,解析这些命令&#xff0c…

趋动科技助力中国移动新型智算中心AI算力池化商用实践

由中国通信标准化协会、中国通信学会指导,CCSA TC610 SDN /NFV /AI标准与产业推进委员会主办的2024年云网智联大会于4月10日-11日在北京召开。 趋动科技联合申报的“中国移动新型智算中心AI算力池化商用实践”,获得2023年度SDN、NFV、网络AI优秀案例征集…

欧美农场小游戏 高端链游 休闲的欧美链游农场 【玫瑰庄园】 高端中英-欧美花园链游

#农场小游戏#链游【玫瑰庄园】 高端中英-欧美花园链游 玫瑰花园一、种子:种子分为五种:白玫瑰、红玫瑰、黑玫瑰、紫罗兰、郁金香。种子通过开启盲盒获得。二、种花:玩家开启盲盒获得的种子,会直接种下,种子种下后&…

深入浅出消息队列----【如何保证消息不重复?】

深入浅出消息队列----【如何保证消息不重复?】 消息一定会重复消息幂等消费改造业务符合天然幂等写法数据库唯一索引redis 唯一判断 本文仅是文章笔记,整理了原文章中重要的知识点、记录了个人的看法 文章来源:编程导航-鱼皮【yes哥深入浅出消…

从零开始的大模型训练教程

近年来,随着人工智能技术的迅猛发展,大模型(Large Models)成为了业界关注的焦点。这些模型,尤其是那些基于Transformer架构的自然语言处理模型,如GPT系列、BERT等,在各种任务上取得了前所未有的…