设计模式之门面模式20170728
结构型设计模式之门面模式:
一、含义
门面模式也叫做外观模式,是一种比较常用的封装模式,其定义如下:
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,门面模式提供一个高层次的接口,使得子系统更易于使用。
通俗来说,门面模式注重"统一的对象",也就是提供一个访问子系统的接口,除了这个接口不允许有任何访问子系统的行为发生。也就是说,门面对象是外界访问子系统内部的唯一通道。
二、代码说明
1.主要有两个角色
1)门面角色
客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就是说该角色没有实际的业务逻辑,只是一个委托类。
2)子系统角色
可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已。
2.在用C实现过程中也是参考这种思想,以写信过程举例,具体实现如下:
1)门面模式使用场景:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : FacadePatternUsage.c 5 * Description : 门面模式的使用 6 7 book@book-desktop:/work/projects/test/DesignPatterns/FacadePattern$ gcc -o FacadePatternUsage LetterProcess.c Police.c FacadePattern.c FacadePatternUsage.c 8 book@book-desktop:/work/projects/test/DesignPatterns/FacadePattern$ ./FacadePatternUsage 9 填写信的内容......Happy Road NO.666,God Province,Heaven 10 填写收件人地址及姓名......Hello,It's me,do you know who I am?I'm your old lover,I'd like to ...... 11 信件已经检查过了...... 12 把信放到信封中...... 13 邮递信件...... 14 15 * Created : 2017.07.27. 16 * Author : Yu Weifeng 17 * Function List : 18 * Last Modified : 19 * History : 20 ******************************************************************************/ 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include "FacadePattern.h" 25 26 27 28 29 /***************************************************************************** 30 -Fuction : main 31 -Description : 32 -Input : 33 -Output : 34 -Return : 35 * Modify Date Version Author Modification 36 * ----------------------------------------------- 37 * 2017/07/27 V1.0.0 Yu Weifeng Created 38 ******************************************************************************/ 39 int main(int argc,char **argv) 40 { 41 char *strContent="Happy Road NO.666,God Province,Heaven"; 42 char *strAddress="Hello,It's me,do you know who I am?I'm your old lover,I'd like to ......"; 43 g_tModernPostOffice.SendLetter(strContent,strAddress); 44 return 0; 45 }
2)被调用者:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : FacadePattern.c 5 * Description : 门面模式 6 本文件是现代邮局的具体实现(门面角色) 7 以写信过程举例 8 9 * Created : 2017.07.27. 10 * Author : Yu Weifeng 11 * Function List : 12 * Last Modified : 13 * History : 14 ******************************************************************************/ 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "FacadePattern.h" 19 #include "LetterProcess.h" 20 #include "Police.h" 21 22 static T_Police g_tPolice=newPolice; 23 static T_LetterProcess g_tLetterProcess=newLetterProcess; 24 25 void ModernPostOfficeSendLetter(char *i_strContent,char *i_strAddress); 26 const T_ModernPostOffice g_tModernPostOffice={ 27 .SendLetter=ModernPostOfficeSendLetter 28 29 }; 30 31 /***************************************************************************** 32 -Fuction : ModernPostOfficeSendLetter 33 -Description : 公有函数 34 -Input : 35 -Output : 36 -Return : 37 * Modify Date Version Author Modification 38 * ----------------------------------------------- 39 * 2017/07/27 V1.0.0 Yu Weifeng Created 40 ******************************************************************************/ 41 void ModernPostOfficeSendLetter(char *i_strContent,char *i_strAddress) 42 { 43 g_tLetterProcess.WriteContent(i_strContent); 44 g_tLetterProcess.FillEnvelope(i_strAddress); 45 g_tPolice.CheckLetter(); 46 g_tLetterProcess.LetterIntoEnvelope(); 47 g_tLetterProcess.SendLetter(); 48 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : FacadePattern.h 5 * Description : 门面模式 6 7 * Created : 2017.07.27. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #ifndef FACADE_PATTERN_H 14 #define FACADE_PATTERN_H 15 16 17 typedef struct ModernPostOffice//门面角色 18 { 19 void (*SendLetter)(char *i_strContext,char *i_strAddress); 20 21 }T_ModernPostOffice;//实现封装(封装写信过程,内部过程对高层透明,高内聚) 22 23 const T_ModernPostOffice g_tModernPostOffice; 24 25 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : LetterProcess.c 5 * Description : 门面模式 6 本文件是写信过程的具体实现 7 8 * Created : 2017.07.27. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include"stdio.h" 15 #include"malloc.h" 16 #include"stdlib.h" 17 #include"string.h" 18 #include"LetterProcess.h" 19 20 21 /***************************************************************************** 22 -Fuction : WriteContent 23 -Description : 公有函数 24 -Input : 25 -Output : 26 -Return : 27 * Modify Date Version Author Modification 28 * ----------------------------------------------- 29 * 2017/07/27 V1.0.0 Yu Weifeng Created 30 ******************************************************************************/ 31 void WriteContent(char *i_strContent) 32 { 33 printf("填写信的内容......%s\r\n",i_strContent); 34 } 35 36 /***************************************************************************** 37 -Fuction : FillEnvelope 38 -Description : 公有函数 39 -Input : 40 -Output : 41 -Return : 42 * Modify Date Version Author Modification 43 * ----------------------------------------------- 44 * 2017/07/27 V1.0.0 Yu Weifeng Created 45 ******************************************************************************/ 46 void FillEnvelope(char *i_strAddress) 47 { 48 printf("填写收件人地址及姓名......%s\r\n",i_strAddress); 49 } 50 51 /***************************************************************************** 52 -Fuction : LetterIntoEnvelope 53 -Description : 公有函数 54 -Input : 55 -Output : 56 -Return : 57 * Modify Date Version Author Modification 58 * ----------------------------------------------- 59 * 2017/07/27 V1.0.0 Yu Weifeng Created 60 ******************************************************************************/ 61 void LetterIntoEnvelope() 62 { 63 printf("把信放到信封中......\r\n"); 64 } 65 66 /***************************************************************************** 67 -Fuction : SendLetter 68 -Description : 公有函数 69 -Input : 70 -Output : 71 -Return : 72 * Modify Date Version Author Modification 73 * ----------------------------------------------- 74 * 2017/07/27 V1.0.0 Yu Weifeng Created 75 ******************************************************************************/ 76 void SendLetter() 77 { 78 printf("邮递信件......\r\n"); 79 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : LetterProcess.h 5 * Description : 门面模式 6 写信过程 7 8 * Created : 2017.07.27. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #ifndef LETTER_PROCESS_H 15 #define LETTER_PROCESS_H 16 17 18 typedef struct LetterProcess 19 { 20 void (*WriteContent)(char *i_strContent); 21 void (*FillEnvelope)(char *i_strAddress); 22 void (*LetterIntoEnvelope)(); 23 void (*SendLetter)(); 24 }T_LetterProcess; 25 26 27 void WriteContent(char *i_strContent); 28 void FillEnvelope(char *i_strAddress); 29 void LetterIntoEnvelope(); 30 void SendLetter(); 31 #define newLetterProcess {WriteContent,FillEnvelope,LetterIntoEnvelope,SendLetter} 32 33 34 35 36 37 38 39 40 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : Police.c 5 * Description : 门面模式 6 本文件是警察的具体实现 7 8 * Created : 2017.07.27. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include"stdio.h" 15 #include"malloc.h" 16 #include"stdlib.h" 17 #include"string.h" 18 #include"Police.h" 19 20 /***************************************************************************** 21 -Fuction : CheckLetter 22 -Description : 公有函数 23 -Input : 24 -Output : 25 -Return : 26 * Modify Date Version Author Modification 27 * ----------------------------------------------- 28 * 2017/07/27 V1.0.0 Yu Weifeng Created 29 ******************************************************************************/ 30 void CheckLetter() 31 { 32 printf("信件已经检查过了......\r\n"); 33 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : Police.h 5 * Description : 门面模式 6 警察(检查信件) 7 * Created : 2017.07.27. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #ifndef POLICE_H 14 #define POLICE_H 15 16 17 typedef struct Police 18 { 19 void (*CheckLetter)(); 20 21 }T_Police; 22 23 void CheckLetter(); 24 #define newPolice {CheckLetter} 25 26 27 #endif
3)执行结果:
book@book-desktop:/work/projects/test/DesignPatterns/FacadePattern$ gcc -o FacadePatternUsage LetterProcess.c Police.c FacadePattern.c FacadePatternUsage.c
book@book-desktop:/work/projects/test/DesignPatterns/FacadePattern$ ./FacadePatternUsage
填写信的内容......Happy Road NO.666,God Province,Heaven
填写收件人地址及姓名......Hello,It's me,do you know who I am?I'm your old lover,I'd like to ......
信件已经检查过了......
把信放到信封中......
邮递信件......
4)详细代码:
https://github.com/fengweiyu/DesignThinking/tree/master/DesignPatterns/StructuralDesignPatterns/FacadePattern
三、使用场景
1.为一个复杂的模块或子系统提供一个供外界访问的接口
2.子系统相对独立---外界对子系统的访问只要黑箱操作即可
3.预防低水平人员带来的风险扩散
为降低低水平人员的代码质量对整体项目的影响风险,一般的做法就是让其只能在指定的子系统中开发,然后再提供门面接口进行访问操作。
四、优点
1.减少系统的相互依赖
所有的依赖都是对门面对象的依赖,与子系统无关
2.提高了灵活性
依赖少了,灵活性自然提高了。不管子系统内部如何变化,只要不影响到门面模式即可。
3.提高安全性
想外界可以访问子系统的哪些业务就开通哪些逻辑,不在门面上开通的方法,外界无法访问。
五、缺点
门面模式最大的缺点就是不符合开闭原则,对修改关闭,对扩展开放。一旦系统投产后发现有一个小错误,唯一能做的就是修改门面角色的代码,这个风险相当大,所以就需要在设计的时候慎之又慎,多思考即便才会有好收获。
六、门面模式的注意事项
1.一个子系统可以有多个门面
一般情况下,一个子系统只要有一个门面足够在什么情况下一个子系统有多个门面呢?以下列举了几个:
1)门面已经庞大到不能忍受的程度
2)子系统可以提供不同访问路径
比如有两个门面,一个可以完整的访问所有业务逻辑,另一个只能访问子系统的某一个方法
2.门面不参与子系统内的业务逻辑
门面对象只是提供一个访问子系统的一个路径而已,它不应该也不能参与具体的业务逻辑,否则就会产生一个倒依赖的问题:子系统必须依赖门面才能被访问,这是设计上一个严重错误,不仅违反了单一职责原则,同时也破坏了系统的封装性。
在门面模式中,门面角色应该是稳定的,它不应该经常变化(变化肯定就不能保证稳定运行了),一个系统一旦投入运行它就不应该被改变,它是一个系统对外的接口。但是,业务逻辑是会经常变化的,所以我们把变化的封装在子系统内部,这样,对外界的访问者来说,都还是同一个门面,同样的方法,也就是稳定的。
七、与其他模式的区别
1、门面模式与中介者模式的区别:
门面模式为复杂的子系统提供一个统一的访问界面,它定义的是一个高层接口,该接口使得子系统更加容易使用,避免外部模块深入到子系统内部而产生与子系统内部细节耦合的问题。
中介者模式使用一个中介对象来封装一系列同时对象的交互行为,它使各对象之间不再显式地引用,从而使其耦合松散,建立一个扩展的应用架构。
具体来说,门面模式是以封装和隔离为主要任务,而中介者模式则是以调和同事类之间的关系为主,因为要调和,所以具有了部分的业务逻辑控制。两者的主要区别如下:
1)功能区别
门面模式只是增加了一个门面,它对子系统来说没有增加任何的功能,子系统若脱离门面模式是完全可以独立运行的。
而中介者模式则增加了业务功能,它把各个同事类中的原有耦合关系移植到了中介者,同事类不可能脱离中介者而独立存在,除非是想增加系统的复杂性和降低扩展性。
2)知晓状态不同
对门面模式来说,子系统不知道有门面存在,而对中介者来说,每个同事类都知道中介者存在,因为要依靠中介者调和同时之间的关系,他们对中介者非常了解。
3)封装程度不同
门面模式是一种简单的封装,所有的请求处理都委托给子系统完成,而中介者模式则需要有一个中心,有中心协调同事类完成,并且中心本身也完成部分业务,它属于更进一步的业务功能封装
2、门面模式与其他包装模式的区别:
自己不处理让其他人处理,这种类型的模式定义一个名字,叫做包装模式。包装模式包括:装饰模式、适配器模式、门面模式、代理模式、桥梁模式。
5个包装模式都是通过委托的方式对一个对象或一系列对象施行包装,有了包装,设计的系统才更加灵活、稳定,并且极具扩展性。从实现的角度来看,它们都是代理的一种具体表现形式,它们在使用场景上的区别如下:
1)代理模式主要用在不希望展示一个对象内部细节的场景中,此外,代理模式还可以用在一个对象的访问需要限制的场景中。
2)装饰模式是一种特殊的代理模式,它倡导的是在不改变接口的前提下为对象增强功能,或者动态添加额外职责。就扩展性而言,它比子类更灵活。
3)适配器模式的主要意图是接口转换,把一个对象的接口转换成系统希望的另外一个接口。这里的系统指的不仅仅是一个应用,也可能是某个环境,比如通过接口转换可以屏蔽外界接口,以免外界接口深入系统内部,从而提高系统的稳定性和可靠性
4)桥梁模式是在抽象层产生耦合,解决的是自行扩展的问题,它可以使两个有耦合关系的对象互不影响地扩展。
5)门面模式是一个粗粒度的封装,它提供一个方便访问子系统的接口,不具有任何的业务逻辑,仅仅是一个访问复杂系统的快速通道,没有它,子系统照样运行。