2018-09-20 01:33:12
外观模式(Facade Pattern)
还是用大话设计模式中的例子:股票和基金来说明外观模式。股票买入者直接操作股票,他需要了解几千只股票的各种信息还需要预测它的涨跌,这样买入者和股票直接有着直接的联系,在软件开发种,这就是高耦合(模块和模块之间的联系过多)。买入基金,则由专业的基金经理人操作用户的资源,买入者只需要和基金经理人打交道,具体股票的细节,则由基金经理人来处理。
外观模式(Facade Pattern)又称门面模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
UML类图
其中:SubSystemOne、SubSystemTwo、SubSystemThree、SubSystemFour 构成了一个子系统。
Facade:外观类,知道哪些子系统,它们有哪些功能,一般Client把像子系统的请求委托给Facade,然后Facade再把这个请求转给适合的子系统对象。(System和Facade其实是聚合关系,它们之间没有太多的耦合性)
SubSystem:子系统,子系统可以同时有多个,一个系统可以是类的集合或者是一个单独的类。每个子系统可以单独被Client调用也可以被Facade调用,对于Client来说它不知道有Facade的存在,Facade对子系统而言就是一个Client。
外观模式的优缺点
优点:
1.Client只与Facade打交道,降低了Client代码的复杂度。
2.降低了Client和System的耦合度,子系统有调整时不会影响到Client或者影响较小,能够通过调整Facade来适应子系统的改变。
3.降低了大型软件中的编译依赖性,并简化了系统在不同平台之间而定移植过程,因为设计良好的子系统,一般而言是相互独立的,一个系统的改变不会影响到其它子系统,而子系统的内部变化(指实现细节)也不会影响到外观,所以只需要编译有变化的子系统即可(对GCC编译器)。
4.模式仅提供了一个访问子系统的统一入口,但是并不阻止用户直接使用子系统类。
缺点:
1.不能很好地限制Client使用子系统,如果要给Client添加使用限制,将可能是整个模式丧失它的灵活性,也会增加其复杂度(试想一下为每个子系统添加定制化的限制,在实现是将会有多复杂)
2.在不引入抽象外观类(Facade)的情况下,增加子系统,要对应的调整Facade和Client(考虑下简单工厂模式),这会违背开放-封闭原则。
使用场景
- 当要为一个复杂子系统提供一个简单接口时。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- Client 与多个子系统之间存在很大的依赖性。引入外观类将子系统与 Client 以及其他子系统解耦,可以提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口。层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
代码示例
问题模型:假设我们在开发一个GUI程序,通过界面我们能够产生一组通用数据,但是这组通用数据需要被不同的子系统按需选择,并进行对应的处理。比如我们能在bash终端输入不同的命令调用不同的处理程序。我们假设这是一个外观模式(但真实的应用情况不是这样,因为,linux下的各种命令实际上是由个人开发者自行开发的程序,在使用时,bash终端输入程序名 参数即可使用命令提供的服务)。那么现在main函数就是客户代码,S1表示调用子系统S1执行某种操作,S2表示调用S2执行某种操作等等。网上有个电商的例子,我觉得比较好,它没有我这个这么理想化,子系统之间的数据没有耦合。
1.3个子系统
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef SUBSYSTEMA_H_ #define SUBSYSTEMA_H_ #include <iostream> class SubSystemA { public: void methodA() { std::cout << "I am SystemA!" << std::endl; } SubSystemA() = default; ~SubSystemA() = default; }; #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef SUBSYSTEMB_H_ #define SUBSYSTEMB_H_ #include <iostream> #include <ctime> class SubSystemB { public: void methodB() { auto systTime = time(nullptr); tm *struSysTime = localtime(&systTime); char szTime[16] = {0}; sprintf(szTime,"%04d-%02d-%02d",struSysTime->tm_year+1990,struSysTime->tm_mon+1,struSysTime->tm_mday); std::cout << "Today is:" << szTime << std::endl; } SubSystemB() = default; ~SubSystemB() = default; }; #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef SUBSYSTEMC_H_ #define SUBSYSTEMC_H_ #include <iostream> #include <ctime> class SubSystemC { public: void methodC() { auto systTime = time(nullptr); tm *struSysTime = localtime(&systTime); char szTime[16] = {0}; sprintf(szTime,"%02d:%02d:%02d",struSysTime->tm_hour,struSysTime->tm_min,struSysTime->tm_sec); std::cout << "Now Time is:"<< szTime << std::endl; } SubSystemC() = default; ~SubSystemC() = default; }; #endif
2.Facade外观类,也是这个模式的核心
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#ifndef FACADE_H_ #define FACADE_H_ #include "SubSystemA.h" #include "SubSystemB.h" #include "SubSystemC.h" #include <string> class Facade { public: void noteSubSystem(const std::string strParam); Facade() = default; ~Facade() = default; private: SubSystemA m_objSubSystemA; SubSystemB m_objSubSystemB; SubSystemC m_objSubSystemC; }; #endif #include "Facade.h" void Facade::noteSubSystem(const std::string strSystemName) { if(strSystemName == "SubSystemA") m_objSubSystemA.methodA(); else if(strSystemName == "SubSystemB") m_objSubSystemB.methodB(); else if(strSystemName == "SubSystemC") m_objSubSystemC.methodC(); else std::cout << "Param Error" << std::endl; }
3.客户端代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "Facade.h" using namespace std; int main(int argc,char*argv[]) { if(argc != 2) { std::cout << "The count of param is Error!" <<std::endl; return (0); } std::string strParam = argv[1]; Facade objFacade; objFacade.noteSubSystem(strParam); return (1); }
外观模式的使用:
1.在设计阶段就要有意识的把不同的层分离(三层架构:数据访问层、业务逻辑层、表示层,在层与层之间建立外观Facade)
2.开发阶段,子系统因为不断的重构变的越来越复杂。增加外观模式。可以提供一个简单的接口,减少它们之间的依赖
3.为新系统开发一个外观Facade类,来提供设计粗糙或高度负责的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有的复杂工作。
d