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

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

一、基础概念

 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

相关文章:

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

一、基础概念 1.1、外观模式的简介 外观模式的本质是【封装交互、简化调用】&#xff1b; 外观模式的说明&#xff1a;就是通过引入一个外观类&#xff0c;在这个类里面定义客户端想要的简单方法&#xff0c;然后在这些方法里面实现&#xff1b;由外观类再去分别调用内部的多个…...

永磁同步电机控制算法-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;…...

MyBatis-Plus 实战:优雅处理 JSON 字段映射(以 JSONArray 为例)

&#x1f3af;MyBatis-Plus 实战&#xff1a;优雅处理 JSON 字段映射&#xff08;以 JSONArray 为例&#xff09; &#x1f468;‍&#x1f4bb; 作者&#xff1a;William Dawson &#xff5c;&#x1f4c5; 更新日期&#xff1a;2025-04-21 &#x1f680; 标签&#xff1a;MyB…...

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

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

PyTorch深度学习框架60天进阶学习计划 - 第47天:模型压缩蒸馏技术(一)

PyTorch深度学习框架60天进阶学习计划 - 第47天&#xff1a;模型压缩蒸馏技术&#xff08;一&#xff09; 第一部分&#xff1a;知识蒸馏的温度调节机制详解 欢迎来到我们学习计划的第47天&#xff01;今天我们将深入探讨模型压缩技术中的两个重要方法&#xff1a;知识蒸馏和…...

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

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

java+postgresql+swagger-多表关联insert操作(九)

入参为json&#xff0c;然后根据需要对多张表进行操作&#xff1a; 入参格式&#xff1a; {"username": "车主01","usertel": "11111111111","useridtype": "2","useridcard": null,"proname&qu…...

[密码学基础]国密算法深度解析:中国密码标准的自主化之路

国密算法深度解析&#xff1a;中国密码标准的自主化之路 国密算法&#xff08;SM系列算法&#xff09;是中国自主研发的密码技术标准体系&#xff0c;旨在打破国际密码技术垄断&#xff0c;保障国家信息安全。本文将从技术原理、应用场景和生态发展三个维度&#xff0c;全面解…...

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

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

自注意力机制、多头自注意力机制、填充掩码 Python实现

原理讲解 【Transformer系列&#xff08;2&#xff09;】注意力机制、自注意力机制、多头注意力机制、通道注意力机制、空间注意力机制超详细讲解 自注意力机制 import torch import torch.nn as nn# 自注意力机制 class SelfAttention(nn.Module):def __init__(self, input…...

目标检测篇---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.…...

数据结构-C语言版本(八)字符串

数据结构中的字符串&#xff1a;概念、操作与实战 第一部分 字符串的分类及常见形式 字符串是由零个或多个字符组成的有限序列&#xff0c;是编程中最基础也最重要的数据结构之一。 1. C语言中的字符串表示 字符数组形式 char str1[10] {H, e, l, l, o, \0};字符串字面量…...

Arduino示例代码讲解:Project 07 - Keyboard 键盘

Arduino示例代码讲解:Project 07 - Keyboard 键盘 Project 07 - Keyboard 键盘程序功能概述功能:硬件要求:输出:代码结构全局变量`setup()` 函数`loop()` 函数读取电位器值:打印电位器值:播放音调:运行过程注意事项Project 07 - Keyboard 键盘 /*Arduino Starter Kit e…...

oracle expdp/impdp 用法详解

oracle expdp/impdp 用法详解 创建逻辑目录&#xff0c;该命令不会在操作系统创建真正的目录&#xff0c;最好以system等管理员创建。 create directory db_bak as d:\test\dump; 查看管理理员目录&#xff08;同时查看操作系统是否存在&#xff0c;因为Oracle并不关心该目录是…...

【漏洞复现】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;虚拟机硬盘扩容之前必…...

每日一题算法——移除链表元素、反转链表

移除链表元素 力扣题目链接 我的解法&#xff1a; 注意细节&#xff1a;要删掉移除的元素。 class Solution { public:ListNode* removeElements(ListNode* head, int val) {while(head!nullptr){if(head->valval){headhead->next;}}ListNode* nowhead head;while(n…...

全面理解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;增量相同的两个列的差值是固定的。 让日期与行号 * 天数…...

pytest自动化中关于使用fixture是否影响用例的独立性

第一个问题&#xff1a;难道使用fixture 会影响用例独立吗&#xff1f; ✅ 简单回答&#xff1a; 使用 fixture ≠ 不独立。 只要你的 fixture 是每次测试都能自己运行、自己产生数据的&#xff0c;那么测试用例依然是“逻辑独立”的。 ✅ 怎么判断 fixture 是否影响独立性&a…...

Token与axios拦截器

目录 一、Token 详解 1. Token 的定义与作用 2. Token 的工作流程 3. Token 的优势 4. Token 的安全实践 5. JWT 结构示例 二、Axios 拦截器详解 1. 拦截器的作用 2. 请求拦截器 3. 响应拦截器 4. 拦截器常见场景 5. 移除拦截器 三、完整代码示例 四、总结 五、…...