设计模式 (9)——外观模式(Facade Pattern,结构型)

1.概述

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。外观模式(Facade Pattern)属于结构型模式,提供了一个统一的接口(具体类),用来访问子系统的一群接口(具体类)。外观定义了一个高层接口,让子系统更容易使用。

要想使用外观模式,我们需要创建一个函数接口简化而统一的类,用来包装子系统中一个或多个复杂的类。外观模式类结构清晰,容易理解,允许我们让客户和子系统之间避免紧耦合。

类图结构如下:

Client:客户类,通过外观类与子系统进行交互。 Facade:外观类,知道哪些子系统类负责处理请求,将客户端的请求代理给适当的子系统对象。 Subsystem:子系统类,实现子系统功能,处理外观类指派的任务,注意子系统类不含有外观类的引用。

外观模式应用了最少知道原则(Least Knowledge Principle),又称为迪米特法则(Law of Demeter)。该原则要求一个对象减少对其他对象的交互,只与几个“密友”交谈。

最少知道原则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。迪米特法则不希望类之间建立直接的联系,如果真的有需要建立联系,也希望能通过它的友元类来转达。因此,应用迪米特法则有可能造成的一个后果是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系,这在一定程度上增加了系统的复杂度。

最少知道原则在中介者模式中也有应用。

2.外观模式的简单应用

本文我们举武侠的例子,我们把《倚天屠龙记》张无忌当作一个系统,他作为一个武侠,本身分为三个子系统,分别是招式、内功和经脉。

张无忌的三个子系统分别是招式、内功和经脉,创建如下:

//子系统招式
class ZhaoShi {
public:
    void taiJiQuan() {
        cout << "使用着招式太极拳" << endl;
    }
    void qiShangQuan() {
        cout << "使用招式七伤拳"<<endl;
    }
    void shengHuoLing() {
        cout << "使用招式圣火令"<<endl;
    }
};

//子系统内功
class NeiGong {
public:
    void jiuYang(){
        cout << "使用九阳神功"<<endl;
    }
    void qianKun() {
        cout << "使用乾坤大挪移"<<endl;
    }
};

//子系统经脉
class JingMai {
public:
    void jingMai() {
        cout << "开启经脉"<<endl;
    }
};

张无忌有很多的招式和内功,怎么将它们搭配,并对外界隐藏呢?这里的外观类就是张无忌,他负责将自己的招式、内功和经脉通过不同的情况合理的运用。

//外观类张无忌
class ZhangWuJi {
private:
    JingMai jingMai;
    ZhaoShi zhaoShi;
    NeiGong neiGong;

public: 
    ZhangWuJi(){}

    //使用乾坤大挪移
    void qianKun() {
        jingMai.jingMai();//开启经脉
        neiGong.qianKun();//使用内功乾坤大挪移
    }

    //使用七伤拳
    void qiShang() {
        jingMai.jingMai(); //开启经脉
        neiGong.jiuYang(); //使用内功九阳神功
        zhaoShi.qiShangQuan();//使用招式七伤拳
    }
};

初始化外观类的同时将各个子系统类对象创建好。很明显张无忌将各个系统搭配好,如使用七伤拳的话就需要开启经脉和内功九阳神功,使七伤拳的威力发挥到极致。

客户端调用:

int main() {
    ZhangWuJi zhangWuJi;
    //张无忌使用乾坤大挪移
    zhangWuJi.qianKun();
    //张无忌使用七伤拳
    zhangWuJi.qiShang();
}

程序输出结果:

开启经脉
使用乾坤大挪移
开启经脉
使用九阳神功
使用招式七伤拳

当张无忌使用乾坤大挪移或者七伤拳的时候,比武的对手显然不知道张无忌本身运用了什么,同时张无忌也不需要去重新计划使用七伤拳的时候需要怎么做,他已经早就计划好了。如果每次使用七伤拳或者乾坤大挪移时都要计划怎么做很显然会增加成本并贻误战机。另外张无忌也可以改变自己的经脉、内功和招式,这些对比武对手都是隐藏的。

外观模式本身将客户端与子系统的交互封装起来,为用户提供一个高层次的类接口,降低了客户端与子系统的耦合度,当子系统发生改变时,不会影响到客户端代码,使得系统易于使用和维护。同时也隐藏了子系统的具体实现,即使具体的子系统发生了变化,客户端也不会感知到。

3.应用场景和优缺点

应用场景: (1)客户端需要与多个子系统交互时,可使用外观模式。如当维护一个遗留的大型系统时,可能这个系统难以维护和拓展,但因为含有重要功能,新的需求必须依赖于它,则可以使用外观类,来为这个粗糙复杂的遗留代码提供一个简单的类接口,让新系统和外观类交互,而外观类负责与遗留的代码进行交互。 (2)客户端程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。

优点: (1)松散耦合。构建一个有层次结构的子系统时,使用外观模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,则可以让他们通过外观接口进行通信,减少子系统之间的依赖关系。

(2)易于使用。子系统往往会因为不断的重构演化而变得越来越复杂,大多数模式使用时也会产生很多很小的类,这给外部调用他们的用户程序带来了使用的困难,我们可以使用外观类提供一个简单的接口,对外隐藏子系统的具体实现并隔离变化。

(3)编译依赖性。降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程。

缺点: 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开放关闭原则”

4.小结

(1)外观模式属于结构型模式,提供了一个统一的类接口,用来访问子系统的一群类接口。外观定义了一个高层类接口,让子系统更容易使用。 (2)最少知道原则要求一个对象尽量减少对其他对象的交互,只与少数的类对象进行交互。


参考文献

[1]最少知道原则.百度百科 [2]设计模式读书笔记—–外观模式 [3]设计模式(八)外观模式

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的Python

16- vue django restful framework 打造生鲜超市 -购物车功能实现

Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 线上演示地址: http://vueshop.mt...

62211
来自专栏JavaEdge

Java并发编程实战系列11之性能与可伸缩性Performance and Scalability

线程可以充分发挥系统的处理能力,提高资源利用率。同时现有的线程可以提升系统响应性。 但是在安全性与极限性能上,我们首先需要保证的是安全性。 11.1 对性能的...

3665
来自专栏小樱的经验随笔

CTF---Web入门第三题 这个看起来有点简单!

这个看起来有点简单!分值:10 来源: 西普学院 难度:易 参与人数:10515人 Get Flag:3441人 答题人数:4232人 解题通过率:81% 很明...

40512
来自专栏wOw的Android小站

[iOS] 技术文章收藏

现在关注了一些微博,订阅号,博客。每天都能看到不少好文章。现在收藏夹里放了不少文章,我觉得是时候整理一下,把文章分各类,做个目录出来,方便以后查阅。

801
来自专栏用户2442861的专栏

caffe 依赖的作用

1.      Boost库:它是一个可移植、跨平台,提供源代码的C++库,作为标准库的后备。

1141
来自专栏黑白安全

ASLRay:一个可以绕过ASLR的工具

ASLR(Address Space Layout Randomization,即地址空间格局随机化)是指利用随机方式配置数据地址,一般现代系统中都加设这一机制...

661
来自专栏嵌入式程序猿

Bootloader需要你的精心设计

嵌入式产品,我们一般都需要一个bootloader来更新固件和修复bug,一般常用的接口有,UART, CAN, USB, Ethernet,有的还有无线接口,...

1293
来自专栏Java技术栈

为什么比起 IntelliJ IDEA,我更喜欢 Eclipse…

2093
来自专栏IT派

10 个技巧,让你更专业地使用 console 进行 JS 调试

首先,我必须承认这一点,我将利用这个平台从我的开发环境中清理出骨架(轮廓)。有时候,我所做的“魔法”(有些人称之为“编码”),并不像我的同事在为他们展示这些宏伟...

1010
来自专栏腾讯Bugly的专栏

手游热更新方案xLua开源:Unity3D下Lua编程解决方案

导语 xLua是Unity3D下Lua编程解决方案,自2016年初推广以来,已经应用于十多款腾讯自研游戏,凭借其出色的性能,易用性,扩展性而广受好评。 而就在前...

3546

扫码关注云+社区

领取腾讯云代金券