设计模式系列-外观模式

一、上篇回顾

上篇我们主要讲述了创建型模式中的最后一个模式-原型模式,我们主要讲述了原型模式的几类实现方案,和原型模式的应用的场景和特点,原型模式

适合在哪些场景下使用呢?我们先来回顾一下我们上篇讲述的3个常用的场景。

1、我们在运行态的时候,动态的创建一个动态类型的对象的时候,可能我们使用原型模式,可以动态的创建指定类型的副本,这无疑是好的选择,否

则如果通过我们前面讲述的几个创建型模式来实现的话,效率和代价上是非常大的。

2、有的时候我们需要对比一个对象在处理前和处理后进行对象状态的对比,对比是否处理后对象的状态是否发生变化,或者是其他的要求。这个时候

通过原型模式来克隆对象的副本,远比通过引入其他的Factory或者abstract Factory 来的有效和更容易实现。

3、如果我们发现有一类这样的对象,这类对象通常来说比较简单,并且这类对象之间的差别很有规律,并且这类对象数量一般有限,那么这个时候,

我们通过原型模式来做的话,通过一个对象来复制创建其他类型的对象可能比通过引入其他的Factory或者abstract Factory 更容易实现,而且只需要对

象本身提供一个Clone()方法即可。

4、有的时候我们的项目中有这样的情况,我们是在别人的功能的基础上进行扩展,我们有不能修改现有的程序,如果这个应用程序是基于其他类型的

创建型模式,那么如果我们在系统中新增一个类型的时候,我们需要修改统一的创建型模式中的代码,不管是修改配置文件还是具体的功能代码,无疑都是

要修改的,那么如果我们通过原型模式的话,只需要在新增类型的对象内部,提供一个克隆方法即可,完成新对象的创建。

通过上面的情况,那么我们也能大概看出来原型模式的有一个前提,就是必须是基于对象之上调用Clone()方法完成对象的复制,如果没有创建这个对

象的话,可能不能直接使用该方法。

我们也讲述了,对于Clone()对象的时候,深复制和浅复制的情况,还包括通过序列化对象的形式来完成对象的深复制。

二、摘要

本文主要是讲述结构型模式中一个比较常用的模式-外观模式,这个模式呢, 有个最大的特点将细粒度的对象包装成粗粒度的对象 ,应用程序通过

访问这个外观对象,来完成细粒度对象的调用,外观模式一般是分布式应用和系统架构中的应用服务层的设计中常用的方式,并且一般结合外观模式+DTO

来完成服务层的设计,提供分布式应用服务的高效服务,外观模式我们可以这样理解,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具

体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性。本文将会从以下几个方面进行讲述:

1、外观模式的使用场景和特点

2、外观模式的实现方案。

3、总结外观模式。

我们这里先给出一个外观模式的原理图:

[外链图片转存中…(img-uEw5sy36-1694043709816)]这是未使用外观模式之前的情况,下面给出使用外观模式后的情形:

clip_image002通过外观对象来组织细粒度的服务的调用,外观对象提供给外部应用程序可

以使用的服务,而具体的调用细粒度的过程则被外观对象给封装起来,当然这个过程就是封装变化的部分,而将变化的部分与应用程序进行隔离,无疑对程

序的易用性和可维护性都是很大的提高。

三、本文大纲

a、上篇回顾。

b、摘要。

c、本文大纲。

d、外观模式的特点及使用场景。

e、外观模式的实现方案。

f、外观模式使用总结。

g、系列进度。

h、下篇预告。

四、外观模式的特点及使用场景

外观模式的主要思想是将复杂的细粒度的对象服务包装成简单的易使用的粗粒度的功能服务,我们大家最容易理解和知道的外观模式就是,使用的API

接口的封装,我们将第三方的API接口引入到我们的项目中的时候,我们需要对这些接口进行包装,将细粒度的具体调用过程进行包装成外观类的形式,通

过外观类来进行统一的调用。我们平时把一些常用的公共方法也可以简易的称之为外观模式,我们将复杂的细粒度的功能,包装成一个比较通用的简易的的

粗粒度的功能。我们来看看哪些场景下,我们使用外观模式很适合呢?

1、我们在使用第三方类库或者API的时候,我们通过本地的API接口的封装,来完成对第三方API接口的粗粒度外观对象,通过这个外观对象可以很容

易的完成服务的调用。我们这里举例说明吧,例如现在我有一个发送手机短信的API接口,是第三方提供给我的API接口,那么我如何包装呢?

下面给出对API封装的相关代码和说明

public class MessageHelper
{
private static readonly MessageHelper instance = new MessageHelper();

#region API接口

[DllImport(“EUCPComm.dll”, EntryPoint = “SendSMS”)] //即时发送
private static extern int SendSMS(string sn, string mn, string ct, string priority);

[DllImport(“EUCPComm.dll”, EntryPoint = “SendSMSEx”)] //即时发送(扩展)
private static extern int SendSMSEx(string sn, string mn, string ct, string addi, string priority);

[DllImport(“EUCPComm.dll”, EntryPoint = “SendScheSMS”)] // 定时发送
private static extern int SendScheSMS(string sn, string mn, string ct, string ti, string priority);

#endregion

#region 对上面的API包装后的方法

public int SendSMSEx1(string sn, string mn, string ct, string addi, string priority)
{
return SendSMSEx(sn, mn, ct, addi, priority);
}

public int SendSMS1(string sn, string mn, string ct, string priority)
{
return SendSMS(sn, mn, ct, priority);
}

public int SendScheSMS1(string sn, string mn, string ct, string ti, string priority)
{
return SendScheSMS(sn, mn, ct, ti, priority);
}

#endregion
}

相关的测试代码:

static void Main(string[] args)
{
//相关的测试代码
//调用外观对象中的服务
MessageHelper.instance.SendSMS1(“”, “”, “”, “”);
}

2、我们在架构设计的过程中,一次的功能访问可能需要同时的调用很多个对象,那么如果我们在服务调用的时候,能够在应用程序调用中一次就能完

成所有要同时调用的对象那该多好啊,外观模式无疑是最好的原则,特别是在分布式应用中,通过远程调用服务,通过外观模式降低应用程序与服务的交互

次数,同时可以降低应用程序的复杂性。外观模式+DTO,提供远程服务调用的性能,这些都是好的设计方式。我们来看看简单的示例吧,我想我们更

能了解其中的奥妙。看图说话吧,我们这里以一次远程同步服务为例。

未使用外观模式前:

clip_image003一个简单的同步服务,由于应用程序在这次服务中为了完成同步操作,必须进行3次远程连接来进

行把3个对象进行同步,那么如果我们使用外观对象之后呢,我们只需要访问一次即可完成3个对象的同步。这无疑提高了系统的性能和效率。

[外链图片转存中…(img-uNaCtzwz-1694043709817)]并且通过DTO来进行传输的话,可以提供远程服务调用的访问此时和效率。

五、外观模式的实现方案

5.1 外观模式的经典实现

我们先来看看外观模式的经典实现,我们这里已二进制流序列化服务外观为例来说明下经典实现吧

定义一个二进制序列化外观类:

public class SerializationFacede
{
public string BinarySerializationObjToString(object target)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, target);

byte[] targetArray = stream.ToArray();

return Convert.ToBase64String(targetArray);
}
}

public object DerializationStringToObj(string target)
{
byte[] targetArray = Convert.FromBase64String(target);
using (MemoryStream stream = new MemoryStream(targetArray))
{
return new BinaryFormatter().Deserialize(stream);
}
}

public T Derialization(string target)
{
return (T)DerializationStringToObj(target);
}
}

我们这里给出相关的测试代码:

static void Main(string[] args)
{
//外观类
SerializationFacede facede = new SerializationFacede();
//测试对象类
Product product = new Product();

//序列化对象
string productString= facede.BinarySerializationObjToString(product);
//反序列化对象
product = facede.Derialization(productString);
}

通过上面的代码我们可以看出,其实外观类也可以以静态方法的形式来提供,提供一个统一的访问入口,这里可以使用我们前面讲述的单例模式来解决这个

问题。或者提供一个外观对象的创建型工厂来完成创建,而不是通过new()的方式来使用。

我们可以改进一下上面的外观模式,通过定义接口,来解耦客户端程序的调用,通过提供一个接口,客户调用通过接口的形式来调用,无疑就可以解

决这样依赖关系:

我们先来看看接口的定义形式:

///
/// 序列化服务的外观接口
///
public interface ISerializationFace
{
string SerializableToString(object target);

object DerializableToObject(string target);

T Derializable(string target);
}

我们分别实现SOAP与二进制的形式来实现我们定义的服务外观接口:

二进制序列化服务:

public class BinarySerializationFace : ISerializationFace
{
#region ISerializationFace 成员

public string SerializableToString(object target)
{
throw new NotImplementedException();
}

public object DerializableToObject(string target)
{
throw new NotImplementedException();
}

public T Derializable(string target)
{
throw new NotImplementedException();
}

#endregion
}

SOAP序列化服务:

public class SoapSerializationFace : ISerializationFace
{
#region ISerializationFace 成员

public string SerializableToString(object target)
{
throw new NotImplementedException();
}

public object DerializableToObject(string target)
{
throw new NotImplementedException();
}

public T Derializable(string target)
{
throw new NotImplementedException();
}

#endregion
}

测试代码如下:

static void Main(string[] args)
{
//外观类
ISerializationFace facede = new SoapSerializationFace();
//测试对象类
Product product = new Product();

//序列化对象
string productString = facede.SerializableToString(product);
//反序列化对象
product = facede.Derializable(productString);
}

这样我们就提高了外观模式的灵活性。

5.2、外观模式的其他考虑

5.2.1-传统外观模式的扩展

上面给出的外观模式,我们在具体的测试代码中还是直接通过new()具体的序列化对象的形式,我们这里可以进行改进,通过工厂模式,或者是通过配

置文件的形式来解耦,一般可能外观类不多的情况下,通过配置文件的方式来进行解耦是不错的选择,而不用提供单独的工厂去创建。

我们可以通过如下的形式来改进上面的方案,例如我们的配置文件的格式定义如下:

<?xml version="1.0" encoding="utf-8" ?>

那么我们看看序列化工厂带示例代码

public class SerializationFactory
{
public static ISerializationFace Create()
{
//配置文件中读取的Type类型
string type = XMLHelper.GetSectionValue(“”);
return (ISerializationFace)Activator.CreateInstance(Type.GetType(type));
}
}

我们来看看具体的测试代码:

static void Main(string[] args)
{
//外观类
ISerializationFace facede = SerializationFactory.Create();
//测试对象类
Product product = new Product();

//序列化对象
string productString = facede.SerializableToString(product);
//反序列化对象
product = facede.Derializable(productString);
}

5.2.2-传统外观模式的扩展

下面给我们来看看另外一种形式的外观模式中的DTO+外观模式的实例实现代码

我们看看DTO的形式:

///
/// DTO(数据传输对象),也可以称之为数据载体
///
public class DTO
{

private Product _product;
private List _orderList;
//全部都是数据信息或者是其他的引用对象信息
public Product Product
{
get
{
return this._product;
}
set
{
this._product = value;
}
}
public List Product
{
get
{
return this._orderList;
}
set
{
this._orderList = value;
}
}

}

具体使用DTO对象的外观类代码如下:

///
/// 远程访问服务
///
public class AccessService
{
bool GetService(DTO dto)
{
return true;
}

DTO GetData()
{
return new DTO();
}
}

通过这样的简易的方式即可完成服务的访问。

程序的测试代码如下:

static void Main(string[] args)
{
//外观类
AccessService service = new AccessService();

DTO dto= service.GetData();
//TODO…
}

通过上面的代码,我们完成了最简单的远程外观的访问服务,远程的外观服务还可以通过WCF的形式来完成,由于WCF内置集成了Remoting和

WebService的形式调用,或者是socket的形式。我这里就不详细的介绍了

六、外观模式使用总结

外观模式作为结构型模式中的一个简单又实用的模式,外观模式通过封装细节来提供大粒度的调用,直接的好处就是,封装细节,提供了应用写程序

的可维护性和易用性。外观模式一般应用在系统架构的服务层中,当我们是多个不同类型的客户端应用程序时,比如一个系统既可以在通过Web的形式访

问,也可以通过客户端应用程序的形式时,可能通过外观模式来提供远程服务,让应用程序进行远程调用,这样通过外观形式提供服务,那么不管是什么样

的客户端都访问一致的外观服务,那么以后就算是我们的应用服务发生变化,那么我们不需要修改没一个客户端应用的调用,只需要修改相应的外观应用即

可。

七、系列进度

创建型

1、系统架构技能之设计模式-单件模式

2、系统架构技能之设计模式-工厂模式

3、系统架构技能之设计模式-抽象工厂模式

4、系统架构技能之设计模式-创建者模式

5、系统架构技能之设计模式-原型模式

结构型

1、系统架构技能之设计模式-组合模式

2、系统架构技能之设计模式-外观模式

3、系统架构技能之设计模式-适配器模式

4、系统架构技能之设计模式-桥模式

5、系统架构技能之设计模式-装饰模式

6、系统架构技能之设计模式-享元模式

7、系统架构技能之设计模式-代理模式

行为型

1、系统架构技能之设计模式-命令模式

2、系统架构技能之设计模式-观察者模式

3、系统架构技能之设计模式-策略模式

4、系统架构技能之设计模式-职责模式

5、系统架构技能之设计模式-模板模式

6、系统架构技能之设计模式-中介者模式

7、系统架构技能之设计模式-解释器模式

八、下篇预告

下篇将会针对外观模式进行讲述,该模式也是结构型模式中很有特点设计模式之一,该 模式是将现有系统中的一些细粒度的东西通过外观对象包装起来,

在应用程序中访问这些方法的时候,通过外观类的形式,提供统一的访问入口,并且具体的细节,应用程序并不需要知道,这样就会降低程序调用的复杂

性,由于本人水平有限,不足或者有错误的地方,请大家批评指正,请大家继续支持我,谢谢。

九、Demo下载

本文Demo

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++项目实战——基于多设计模式下的同步异步日志系统-③-前置知识补充-设计模式

文章目录 专栏导读六大原则单例模式饿汉模式懒汉模式 工厂模式简单工厂模式工厂方法模式抽象工厂模式 建造者模式代理模式 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿…

【Vue CLI】

node.js安装 https://nodejs.org/download/release/v15.14.0/ 管理员运行cmd node -v 安装npm npm install -g cnpm --registryhttps://registry.npm.taobao.org 查看是否安装成功 npm -v 注册淘宝镜像加速器 npm config set registry https://registry.npm.taobao.org/ 查看…

无涯教程-JavaScript - COUPDAYSNC函数

描述 COUPDAYSNC函数返回从结算日期到下一个息票日期的天数。 语法 COUPDAYSNC (settlement, maturity, frequency, [basis])争论 Argument描述Required/OptionalSettlement 证券的结算日期。 证券结算日期是指在发行日期之后将证券交易给买方的日期。 RequiredMaturity 证…

【SpringMVC】注解、参数传递、返回值和页面跳转的关键步骤

目录 引言 一、常用注解 1.1.RequestMapping 1.2.RequestParam 1.3.RequestBody 1.4.RequestHeader 1.5.PathVariable 二、参数传递 2.1.基础类型String 2.2.复杂类型 2.3.RequestParam 2.4.PathVariable 2.5.RequestBody 2.6.RequestHeader 三、返回值 3.1.vo…

设置Linux CentOS7桥接模式连网

在虚拟机上安装centos7系统后&#xff0c;首要任务就是设置网络。 我们在文章《设置linux centos7连接网络》中讨论了如何设置NAT模式连网。本文讨论如何在设置好NAT模式后&#xff0c;调换为桥接模式。 仍采用图形化方式设置方法。 一、查看物理机网络 把虚拟机设置为桥接…

时序分解 | MATLAB实现基于EWT经验小波变换的信号分解分量可视化

时序分解 | MATLAB实现基于EWT经验小波变换的信号分解分量可视化 目录 时序分解 | MATLAB实现基于EWT经验小波变换的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 EWT经验小波变换 包含频谱相关系数 可直接运行 Matlab代码 1.可自由设置分量个数&…

windows安装向量数据库milvus

本文介绍windows下安装milvus的方法。 一.Docker安装 1.1docker下载 首先到Docker官网上下载docker:Docker中文网 官网 1.2.安装前前期准备 先使用管理员权限打开windows powershell 然后在powershell里面输入下面那命令&#xff0c;启用“适用于 Linux 的 Windows 子系统”…

调整Windows11桌面图标间隔

调整Windows11桌面图标间隔 WinR 快捷键如何使用 在Windows系统中&#xff0c;通过 WinR 的快捷键可以快速打开Windows系统的“运行”窗口&#xff0c;然后在这里输入相应的命令就可以快速执行指定的任务。 具体的操作方法是&#xff0c;同时按下键盘上的Windows键和R键即可。…

android 注解详解

1&#xff0c;注解的概念 注解现在广泛的应用于android的各个开源框架中&#xff0c;不理解注解&#xff0c;我们就无法更好的提升我们的架构能力。那么什么是注解呢&#xff1f;注解&#xff08;Annotation&#xff09;&#xff0c;是JDK5.0 引入的一种注释机制。 注解是元数…

Python基础语法:数据分析利器

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

华为OD机考算法题:食堂供餐

目录 题目部分 解析与思路 代码实现 题目部分 题目食堂供餐题目说明某公司员工食堂以盒饭方式供餐。为将员工取餐排队时间降低为0&#xff0c;食堂的供餐速度必须要足够快。现在需要根据以往员工取餐的统计信息&#xff0c;计算出一个刚好能达成排队时间为0的最低供餐速度。…

LORA项目源码解读

大模型fineturn技术中类似于核武器的LORA&#xff0c;简单而又高效。其理论基础为&#xff1a;在将通用大模型迁移到具体专业领域时&#xff0c;仅需要对其高维参数的低秩子空间进行更新。基于该朴素的逻辑&#xff0c;LORA降低大模型的fineturn门槛&#xff0c;模型训练时不需…

【力扣每日一题】2023.9.3 消灭怪物的最大数量

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目比较长&#xff0c;我概括一下就是有一群怪物&#xff0c;每只怪物离城市的距离都不一样&#xff0c;并且靠近的速度也不一样&#x…

工厂设计模式

github&#xff1a;GitHub - QiuliangLee/pattern: 设计模式 概念 根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式&#xff0c;根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。 简单工厂模式、工厂方法模式和抽象工厂模式有何区别&#xff1f; - 知…

SimVODIS++: Neural Semantic Visual Odometry in Dynamic Environments 论文阅读

论文信息 题目&#xff1a;SimVODIS: Neural Semantic Visual Odometry in Dynamic Environments 作者&#xff1a;Ue-Hwan Kim , Se-Ho Kim , and Jong-Hwan Kim , Fellow, IEEE 时间&#xff1a;2022 来源&#xff1a; IEEE ROBOTICS AND AUTOMATION LETTERS&#xff08;RAL…

shell知识点复习

1、shell能做什么&#xff08; Shell可以做任何事(一切取决于业务需求) &#xff09; 自动化批量系统初始化程序 自动化批量软件部署程序 应用管理程序 日志分析处理程序 自动化备份恢复程序 自动化管理程序 自动化信息采集及监控程序 配合Zabbix信息采集 自动化扩容 2、获取当…

【疑难杂症】解决 git 文件夹不显示绿色图标和红色图标的问题

目录 一、问题描述 二、问题解决前提 【2.1】首先保证电脑本机上有TortoiseGit这个软件 【2.2】TortoiseGit下载官网 【2.3】根据自己电脑位数进行下载&#xff0c;这里下载的是64位 【2.4】下载好之后&#xff0c;一路next进行安装&#xff0c;配置自己的邮箱和用户名 …

【TypeScript学习】—面向对象(四)

【TypeScript学习】—面向对象&#xff08;四&#xff09; 一、面向对象 二、类 三、构造方法 class Dog{name:string;age:number;//构造函数constructor(name:string,age:number){this.namename;this.ageage;}bark(){//在方法中可以通过this来表示当前调用方法的对象//this表…

Springboot整合AOP实现日志的保存

1.定义注解 /*** 系统日志元注解*/ Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface LogFilter {String value() default "" ; } 2.编写切面的实现 Aspect Component public class LogAspect {private static final …

[极客大挑战 2019]FinalSQL(bypass盲注)

这里是数字型注入&#xff0c;选择一个序号 fuzz ?id1这里过滤了很多东西 使用fuzzSQL字典&#xff0c;这是我自己定义编写的一个fuzz字典&#xff0c;内容较少 select from information . tables whereand " or | & union columns updatexml extractvalue databa…