写点什么

【愚公系列】2022 年 05 月 二十三种设计模式 (十)- 外观模式 (Facade Pattern)

作者:愚公搬代码
  • 2022 年 5 月 10 日
  • 本文字数:3078 字

    阅读完需:约 10 分钟

前言

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

一、外观模式(Facade Pattern)

外观模式属于结构型模式,它隐藏了系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。


为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。

二、使用步骤

角色

1、外观角色(Facade)


外观模式的核心,它被客户角色调用,它熟悉子系统的各项功能,可以在内部根据需求预定几种功能的组合;


2、子系统角色(SubSystem)


实现了子系统的功能,它内部可以有系统内的相互交互,也可以由供外界调用的接口。

示例


命名空间 FacadePattern 中包含外观类 Facade,提供公开的 Handle 方法,Haikwan 是海关类,可以通过 Apply 方法从后台取得一个加密的完税凭证 JSON 数据,Decrypt 类为解密类,可以解密海关的 JSON 数据,TaxProof 则是完税凭证类,可以将 JSON 反序列化成一个对象,FileStore 则将完税凭证数据持久化到文件中。本案例尝试通过一个从海关获取数据、解密、反序列化、保存到文件的完整流程来向大家简明扼要的阐述外观模式的使用。


public class Haikwan {     public string Apply(Uri uri) {        Console.WriteLine($"Apply some data from {uri.ToString()}!");        return Const.TEMPLET_HAIKWAN;    } }
复制代码


海关类 Haikwan,包含一个 Apply 方法可以从海关的后台获取一个加密的 JSON 数据。


public class Decrypt {
public string Decipher(string ciphertext) { Console.WriteLine("Deciphering ciphertext!"); Console.WriteLine(Const.LINE_BREAK); Console.WriteLine(ciphertext); Console.WriteLine(Const.LINE_BREAK); return ciphertext; }
}
复制代码


解密类 Decrypt,将加密的 JSON 数据用 Decipher 方法解密成原始 JSON 数据。


public class TaxProof {
public string TaxNo { get; private set; }
public decimal Money { get; private set; }
public DateTime PaymentData { get; private set; }
public void Deserialize(string plaintext) { Console.WriteLine("Creating TaxProof Instance from plaintext!"); TaxNo = "287361039374492-A01"; Money = 1986.1020m; PaymentData = new DateTime(2018, 07, 20); }
}
复制代码


TaxProof 完税凭证类,将 JSON 数据反序列化成实体对象,以便使用类的面向对象语言的优势进行后续的处理。


本例中没有真正实现反序列化的动作,仅仅作为一个演示使用了 Hard Code。在实际开发过程中,推荐使用 Newtonsoft.Json 来处理序列化和反序列化。


public class FileStore    {        public void Store(TaxProof taxProof)        {            Console.WriteLine("Saving taxProof instance to file!");            Console.WriteLine($"TaxProof.TasNo={taxProof.TasNo},");            Console.WriteLine($"TaxProof.TasNo={taxProof.TasNo},");            Console.WriteLine($"TaxProof.TasNo={taxProof.TasNo},");            Console.WriteLine($"TaxProof.TasNo={taxProof.TasNo},");        }    }
复制代码


FileStore 文件保存类,将完税凭证数据持久化到文件中。


public class Facade {
private Haikwan _haikwan = null; private Decrypt _decrypt = null; private TaxProof _taxProof = null; private FileStore _fileStore = null;
public Facade() { _haikwan = new Haikwan(); _decrypt = new Decrypt(); _taxProof = new TaxProof(); _fileStore = new FileStore(); }
public void Handle(Uri uri) { var ciphertext = _haikwan.Apply(uri); var plaintext = _decrypt.Decipher(ciphertext); _taxProof.Deserialize(plaintext); _fileStore.Store(_taxProof); }
}
复制代码


Facade 外观类,这是外观模式的核心类,首先在内部维持对海关类 Haikwan、解密类 Decrypt、完税凭证类 TaxProof、文件保存类 FileStore 的引用,并在构造函数中创建它们,公开的 Handle 方法处理一个完整的从海关获取数据到持久化文件的完整流程。


public class Const {
public const string TEMPLET_HAIKWAN = "{\r\n" + " \"Haikwan\": {\r\n" + " \"TaxNo\": \"287361039374492-A01\",\r\n" + " \"Money\": 1986.1020,\r\n" + " \"PaymentData\": \"\\/Date(1532099596)\\/\"\r\n" + " }\r\n" + "}";
public const string LINE_BREAK = "-------------------------------------------------------------";
public const string HAIKWAN_URI = "http://@copyright#www.customs.gov.cn";
}
复制代码


Const 常量类,统一管理本案例中用到的字符串资源。实际开发过程中不应当出现此类,请参考 2017 年阿里发布的《阿里巴巴 Java 开发手册》,此规则对 C#开发者来说也应当遵守。


public class Program {
private static Facade _facade = null;
public static void Main(string[] args) { _facade = new Facade(); _facade.Handle(new Uri(Const.HAIKWAN_URI));
Console.ReadKey(); }
}
复制代码


调用方的代码,仅仅需要一行代码就完成了一个完整的流程。以下是这个案例的输出结果:


Apply some data from http://@copyright/#www.customs.gov.cn!Deciphering ciphertext!-------------------------------------------------------------{  "Haikwan": {    "TaxNo": "287361039374492-A01",    "Money": 1986.1020,    "PaymentData": "\/Date(1532099596)\/"  }}-------------------------------------------------------------Creating TaxProof Instance from plaintext!Saving taxProof instance to file!TaxProof.TaxNo = 287361039374492-A01,TaxProof.Money = 1986.1020,TaxProof.PaymentData = 2018-07-20 00:00:00!-------------------------------------------------------------
复制代码


<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

总结

优点

1、实现了子系统与客户端之间的松耦合关系;2、客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易。

缺点

1、不符合开闭原则,如果要修改某一个子系统的功能,通常外观类也要一起修改;2、没有办法直接阻止外部不通过外观类访问子系统的功能,因为子系统类中的功能必须是公开的(根据需要决定是否使用 internal 访问级别可解决这个缺点,但外观类需要和子系统类在同一个程序集内)。

使用场景

1、设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式;2、开发阶段,子系统越来越复杂,增加外观模式提供一个简单的调用接口;3、维护一个大型遗留系统的时候,可能这个系统已经非常难以维护和扩展,但又包含非常重要的功能,为其开发一个外观类,以便新系统与其交互。

发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2022.03.01 加入

该博客包括:.NET、Java、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、python、大数据等相关使用及进阶知识。查看博客过程中,如有任何问题,皆可随时沟通。

评论

发布
暂无评论
【愚公系列】2022年05月 二十三种设计模式(十)-外观模式(Facade Pattern)_5月月更_愚公搬代码_InfoQ写作社区