学习设计模式《二》——外观模式

news2025/4/23 3:24:03

一、基础概念

 1.1、外观模式的简介

        外观模式的本质是【封装交互、简化调用】

        外观模式的说明:就是通过引入一个外观类,在这个类里面定义客户端想要的简单方法,然后在这些方法里面实现;由外观类再去分别调用内部的多个模块来实现功能,从而让客户端变得简单;这样一来,客户端就只需要和外观类交互就可以了

        外观模式的实现:对一个子系统来说,外观类不需要很多,可以实现为一个单例; 或直接将外观类中的方法实现为静态方法,将外观类作为一个辅助工具类,方便外部直接调用 。

        外观模式目的:为了让外部减少与子系统内部多个对象或模块的交互,松散耦合,封装了内部细节, 从而让外部能够更简单地使用子系统。

        使用外观模式的注意点:因为外观模式是当做子系统对外的通道,虽然也可以在这里定义一些子系统没有的功能,但不建议这样做【外观应该是包装已有功能,它主要负责组合已有功能来实现客户需要,本身并不进行功能的处理,而不是添加新的实现】。

何时选用外观模式?

1、希望为一个复杂的子系统提供简单的对外通道,简化外部调用;

2、想要让外部程序和抽象类的实现部分松散耦合(使用外观类将子系统与外部客户端分离开,提供子系统的独立性与可移植性);
3、构建多层结构的系统。

外观模式的优缺点
序号外观模式的优点外观模式的缺点
1

松散耦合

(松散了客户端与子系统的耦合关系,让子系统内部模块更容易扩展与维护)

过多或不太合理的外观类容易让人迷惑(即是调用外观类好,还是直接调用模块好)
2

简单易用

(外观类让子系统更加易用,客户端不再需要了解子系统内部实现,也不需要与子系统内部模块交互)

3

 更好的划分访问层次

(合理使用外观类,可以帮助我们更好地划分访问层次【外观类把需暴露给外部的功能都集中提供,而子系统内部更多的方法是内部使用】)

 1.2、现实中的一些外观模式例子

比如我们现实生活中的需要购买台式电脑:可以有两种方式:

        方法一:自己列出所需的各种配件,然后买来各种配件,自己组装(这个方案是好,但是需要对各种电脑配件熟悉,这样才能选择到合适的配件,且需要考虑好各个配件间的兼容性)

        方案二:直接找到专业的装机公司或团体,把自己的需求提出来,然后有装机公司根据要求购买好对于的配件组装调试好给你(这个方案是省心,但是价格会贵一些,综合起来还是比较划算的,是大多数人的选择)【该方案中的专业装机公司或团体就可以看作是外观模式的外观类了】

二、外观模式示例

        在软件开发公司中会有一个为了减少大家复制粘贴工作的代码生成工具,用来生成基础的代码(比如数据库的增删查改【一般会生成三层内容(表现层、业务层、数据层)】),在项目开发中可以直接使用该工具生成基础的代码,然后可以留出更多的时间去实现项目中的业务内容;我们这里仅写一些示意代码,主要是用来展现外观模式:

 2.1、常规实现

1、编写配置模型类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    /// <summary>
    /// 配置模型示意
    /// </summary>
    internal class ConfigModel
    {
        //是否需要生产表现层
        private bool needGenPresentation = true;

        //是否需要生成逻辑层
        private bool needGenBusiness=true;

        //是否需要生成数据层(DAO表示Data Access Object)
        private bool needGenDAO = true;

        public bool NeedGenPresentation { get => needGenPresentation; set => needGenPresentation = value; }
        public bool NeedGenBusiness { get => needGenBusiness; set => needGenBusiness = value; }
        public bool NeedGenDAO { get => needGenDAO; set => needGenDAO = value; }

    }//Class_end
}

2、编写配置管理类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    internal class ConfigManager
    {
        private static ConfigManager configManager = null;
        private static ConfigModel configModel = null;

        public ConfigManager()
        {

        }

        public static ConfigManager GetInstance() 
        {
            if (configManager==null)
            {
                configManager = new ConfigManager();
                configModel = new ConfigModel();
                //读取配置文件,把值设置到ConfigModel中
            }
            return configManager;
        }

        //获取配置的数据
        public ConfigModel GetConfigData()
        {
            return configModel;
        }


    }//Class_end
}

3、编写表现层类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    /// <summary>
    /// 生成表现层模块示意
    /// </summary>
    internal class Presentation
    {
        public void Generate()
        {
            //1、从配置管理里面获取相应的配置信息
            ConfigModel configModel=ConfigManager.GetInstance().GetConfigData();

            if (configModel.NeedGenPresentation)
            {
                //2、按照要求生成对应的表现层代码,并保存为文件
                Console.WriteLine("正在生成表现层代码文件并保存");
            }
        }


    }//Class_end
}

4、编写业务层类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    /// <summary>
    /// 生产逻辑层模块示意
    /// </summary>
    internal class Business
    {
        public void Generate()
        {
            ConfigModel configModel = ConfigManager.GetInstance().GetConfigData();
            if (configModel.NeedGenBusiness)
            {
                Console.WriteLine("正在生成逻辑层的代码文件并保存");
            }
        }

    }//Class_end
}

5、编写数据层类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    /// <summary>
    /// 生成数据层模块示意
    /// </summary>
    internal class DAO
    {
        public void Generate()
        {
            ConfigModel configModel=ConfigManager.GetInstance().GetConfigData();
            if (configModel.NeedGenDAO)
            {
                Console.WriteLine("正在生成数据层的代码文件并保存");
            }
        }

    }//Class_end
}

6、编写客户端实现,需要客户端对接各个类进行了解调用组合

        客户端为了使用生成代码的功能,需要与生成代码子系统内部的多个模块进行交互【对客户端来说,这是比较麻烦的,且如果其中的某个模块发生了变化,还可能引起客户端要随着变化】

using FacadePattern.CodeGenerationV1;

namespace FacadePattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("客户端要实现功能需自己管理不同的子模块与逻辑");
            /***
             * 目前没有配置文件,直接使用默认配置(生成三层模块)
             * 也就是说客户端必须要对这三个模块都有所了解,才能够正确使用;
             * 且客户端为了使用生成代码的功能,需要与生成代码子系统内部的多个模块进行交互
             * 【对客户端来说,这是比较麻烦的,且如果其中的某个模块发生了变化,还可能引起客户端要随着变化】
             * (如何实现?才能让子系统外部的客户端在使用子系统的时候简单的使用子系统内部模块功能,而又不用与子系统内部的多个模块交互?)
             * ***/
            new Presentation().Generate();
            new Business().Generate();
            new DAO().Generate();

        }//Class_end
    }
}

 运行后的结果如下:

 2.2、外观模式

        如何实现?才能让子系统外部的客户端在使用子系统的时候简单的使用子系统内部模块功能,而又不用与子系统内部的多个模块交互?

1、单独创建一个外观类用来调用组合子系统的功能

/***
*	Title:"设计模式" 项目
*		主题:外观模式
*	Description:
*	    基础概念:本质是【封装交互、简化调用】
*	        外观模式:就是通过引入一个外观类,在这个类里面定义客户端想要的简单方法,
*	                  然后在这些方法里面实现;由外观类再去分别调用内部的多个模块来实现功能,
*	                  从而让客户端变得简单;这样一来,客户端就只需要和外观类交互就可以了。
*	                  
*	        外观模式目的:为了让外部减少与子系统内部多个对象或模块的交互,松散耦合,封装了内部细节,
*	                      从而让外部能够更简单地使用子系统
*	                      
*	        使用外观模式的注意点:因为外观模式是当做子系统对外的通道,虽然也可以在这里定义一些子系统
*	                              没有的功能,但不建议这样做【外观应该是包装已有功能,它主要负责组合已有
*	                              功能来实现客户需要,本身并不进行功能的处理,而不是添加新的实现】
*	                              
*	        外观模式的实现:对一个子系统来说,外观类不需要很多,可以实现为一个单例
*	                        或直接将外观类中的方法实现为静态方法,将外观类作为一个辅助工具类,方便外部直接调用                      
*	                              
*	        有外观模式,但可以不使用:虽然有外观类,但如果有需要,外部还是可以绕开外观类,而直接调用
*	                                  某个具体模块功能,这样就能实现兼顾组合功能和细节功能
*	                                  
*		    外观模式优点:
*		                松散耦合(松散了客户端与子系统的耦合关系,让子系统内部模块更容易扩展与维护)
*		                简单易用(外观类让子系统更加易用,客户端不再需要了解子系统内部实现,也不需要与子系统内部模块交互)
*		                更好的划分访问层次(合理使用外观类,可以帮助我们更好地划分访问层次【外观类把需暴露给外部的功能都集中提供,而子系统内部更多的方法是内部使用】)
*		    外观模式缺点:过多或不太合理的外观类容易让人迷惑(即是调用外观类好,还是直接调用模块好)
*		    
*		    何时选用外观模式?
*		                1、希望为一个复杂的子系统提供简单的对外通道,简化外部调用;
*		                2、想要让外部程序和抽象类的实现部分松散耦合(使用外观类将子系统与外部客户端分离开,提供子系统的独立性与可移植性)
*		                3、构建多层结构的系统
*		    
*	Date:2025
*	Version:0.1版本
*	Author:Coffee
*	Modify Recoder:
 ***/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FacadePattern.CodeGenerationV1
{
    /// <summary>
    /// 定义一个子系统的外观对象,统一对外提供方法,外部不用关心与管理内部模块的实现
    /// </summary>
    internal class Facade
    {
        private Facade()
        {
            
        }

        /// <summary>
        /// 直接把客户端需要的功能单独定义一个方法提供出来
        /// </summary>
        public static void Generate()
        {
            //该方法实现的时候,可能会调用到内部的多个模块
            new Presentation().Generate();
            new Business().Generate();
            new DAO().Generate();
        }

    }//Class_end
}

2、客户端可以直接调用外观类的方法(简单明了,客户端不用了解子系统的各个模块与细节)

using FacadePattern.CodeGenerationV1;

namespace FacadePattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("外观模式");
            //客户端直接调用外观对象的方法(简单便捷)
            Facade.Generate();

            Console.ReadLine();


        }//Class_end
    }
}

运行结果如下:

三、项目源码工程

kafeiweimei/Learning_DesignPattern: 这是一个关于C#语言编写的基础设计模式项目工程,方便学习理解常见的26种设计模式https://github.com/kafeiweimei/Learning_DesignPattern

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

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

相关文章

永磁同步电机控制算法-VF控制

一、原理介绍 V/F 控制又称为恒压频比控制,给定VF 控制曲线 电压是频率的tt例函数 即控制电压跟随频率变化而变化以保持磁通恒定不变。 二、仿真模型 在MATLAB/simulink里面验证所提算法&#xff0c;搭建仿真。采用和实验中一致的控制周期1e-4&#xff0c;电机部分计算周期为…

qt 配置 mysql 驱动问题:Cannot load library qsqlmysql;QMYSQL driver not loaded

项目场景&#xff1a; 环境版本&#xff1a; qt &#xff1a;5.14.2 mysql&#xff1a;8.0 windows&#xff1a;10 提示&#xff1a;qt 配置 mysql 驱动&#xff1a; 项目场景&#xff1a;qt 配置 mysql 驱动 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a;…

线性代数 | 知识点整理 Ref 2

注&#xff1a;本文为 “线性代数 | 知识点整理” 相关文章合辑。 因 csdn 篇幅合并超限分篇连载&#xff0c;本篇为 Ref 2。 略作重排&#xff0c;未整理去重。 图片清晰度限于引文原状。 如有内容异常&#xff0c;请看原文。 【数学】线性代数知识点总结 阿巴 Jun 于 2024-…

华为OD机试真题——最小的调整次数/特异性双端队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析&#xff1b; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式&#xff01; 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调…

Flink-01学习 介绍Flink及上手小项目之词频统计

flink简介 官网 概述&#xff1a; 学习Flink具体包括四个关键概念&#xff1a;流数据的持续处理&#xff0c;事件时间&#xff0c;有状态流处理和状态快照。 Apache Flink 是一个开源的流处理框架&#xff0c;旨在处理批处理和实时数据处理&#xff0c;具有高吞吐量和低延迟的…

目标检测篇---R-CNN梳理

目标检测系列文章 第一章 R-CNN 目录 目标检测系列文章&#x1f4c4; 论文标题&#x1f9e0; 论文逻辑梳理1. 引言部分梳理 (动机与思想) &#x1f4dd; 三句话总结&#x1f50d; 方法逻辑梳理&#x1f680; 关键创新点&#x1f517; 方法流程图补充边界框回归 (BBR)1. BBR 的…

C#处理网络传输中不完整的数据流

1、背景 在读取byte数组的场景&#xff08;例如&#xff1a;读取文件、网络传输数据&#xff09;中&#xff0c;特别是网络传输的场景中&#xff0c;非常有可能接收了不完整的byte数组&#xff0c;在将byte数组转换时&#xff0c;因字符的缺失/增多&#xff0c;转为乱码。如下…

HTML 初识

段落标签 <p><!-- 段落标签 -->Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugiat, voluptate iure. Obcaecati explicabo sint ipsum impedit! Dolorum omnis voluptas sint unde sed, ipsa molestiae quo sapiente quos et ad reprehenderit.&l…

MATLAB 训练CNN模型 yolo v4

学生对小车控制提出了更好的要求&#xff0c;能否加入深度学习模型。 考虑到小车用matlab来做&#xff0c;yolo v5及以上版本都需要在pytorch下训练&#xff0c;还是用早期版本来演示。 1 yolov4 调用 参考 trainYOLOv4ObjectDetector (mathworks.com) name "tiny-yo…

【前端】跟着maxkb学习logicflow流程图画法

文章目录 背景1. 选定学习对象-maxkb应用逻辑编排2. 确定实现框架3. 关键逻辑&#xff1a;查看app-node.js4. 学习开始节点绘制流程数据形式 5. 给节点增加表单输入框遇到过的问题 背景 看看前端如何绘制流程图&#xff0c;界面好看点。 "logicflow/core": "1.…

【漏洞复现】CVE-2024-38856(ApacheOfbiz RCE)

【漏洞复现】CVE-2024-38856&#xff08;ApacheOfbiz RCE&#xff09; 1. 漏洞描述 Apache OFBiz 是一个开源的企业资源规划&#xff08;ERP&#xff09;系统。它提供了一套企业应用程序&#xff0c;用于集成和自动化企业的许多业务流程。 这个漏洞是由于对 CVE-2023-51467 的…

超详细VMware虚拟机扩容磁盘容量-无坑版

1.环境&#xff1a; 虚拟机&#xff1a;VMware Workstation 17 Pro-17.5.2 Linux系统&#xff1a;Ubuntu 22.04 LTS 2.硬盘容量 虚拟机当前硬盘容量180G -> 扩展至 300G 3.操作步骤 &#xff08;1&#xff09;在虚拟机关机的状态下&#xff0c;虚拟机硬盘扩容之前必…

全面理解Linux 系统日志:核心文件与查看方法

全文目录 1 Linux 系统日志分类及功能1.1 通用日志1.1.1 ‌/var/log/messages1.1.2 ‌/var/log/syslog 1.2 安全相关日志1.2.1 ‌/var/log/auth.log‌&#xff08;Debian/Ubuntu&#xff09;或 ‌/var/log/secure‌&#xff08;RHEL/CentOS&#xff09;1.2.2 /var/log/audit/au…

机器学习-08-关联规则更新

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中关联规则和协同过滤。 参考 机器学习&#xff08;三&#xff09;&#xff1a;Apriori算法&#xff08;算法精讲&#xff09; Apriori 算法 理论 重点 【手撕算法】【Apriori】关联规则Apriori原理、代码…

Flutter与FastAPI的OSS系统实现

作者&#xff1a;孙嘉成 目录 一、对象存储 二、FastAPI与对象存储 2.1 缤纷云S4服务API对接与鉴权实现 2.2 RESTful接口设计与异步路由优化 三、Flutter界面与数据交互开发 3.1 应用的创建 3.2页面的搭建 3.3 文件的上传 关键词&#xff1a;对象存储、FastAPI、Flutte…

Kubernetes控制平面组件:API Server详解(二)

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…

MySQL-锁机制3-意向共享锁与意向排它锁、死锁

文章目录 一、意向锁二、死锁应该如何避免死锁问题&#xff1f; 总结 一、意向锁 在表获取共享锁或者排它锁时&#xff0c;需要先检查该表有没有被其它事务获取过X锁&#xff0c;通过意向锁可以避免大量的行锁扫描&#xff0c;提升表获取锁的效率。意向锁是一种表级锁&#xf…

报告系统状态的连续日期 mysql + pandas(连续值判断)

本题用到知识点&#xff1a;row_number(), union, date_sub(), to_timedelta()…… 目录 思路 pandas Mysql 思路 链接&#xff1a;报告系统状态的连续日期 思路&#xff1a; 判断连续性常用的一个方法&#xff0c;增量相同的两个列的差值是固定的。 让日期与行号 * 天数…

Tailwind 武林奇谈:bg-blue-400 失效,如何重拾蓝衣神功?

前言 江湖有云,Tailwind CSS,乃前端武林中的轻功秘籍。习得此技,排版如行云流水,配色似御风随形,收放自如,随心所欲。 某日,小侠你奋笔敲码,正欲施展“蓝衣神功”(bg-blue-400),让按钮怒气冲冠、蓝光满面,怎料一招使出,画面竟一片白茫茫大地真干净,毫无半点杀气…

开始放飞之先搞个VSCode

文章目录 开始放飞之先搞个VSCode重要提醒安装VSCode下载MinGW-w64回到VSCode中去VSCode原生调试键盘问题遗留问题参考文献 开始放飞之先搞个VSCode 突然发现自己的新台式机上面连个像样的编程环境都没有&#xff0c;全是游戏了&#xff01;&#xff01;&#xff01;&#xff…