设设计模式之外观模式(Facade)摘录
Facade:
(1)、意图: 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
(2)、动机:将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观(facade)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。
(3)、适用性:在遇到以下情况适用Facade模式:
A、当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
B、客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
C、当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。
(4)、优点:
A、它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
B、它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。Facade模式可以消除复杂的循环依赖关系。这一点在客户程序与子系统是分别实现的时候尤为重要。在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作。Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。
C、如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。
(5)、注意事项:
A、降低客户----子系统之间的耦合度:用抽象类实现Facade而它的具体子类对应于不同的子系统实现,这可以进一步降低客户与子系统的耦合度。这样,客户就可以通过抽象的Facade类接口与子系统通讯。这种抽象耦合关系使得客户不知道它使用的是子系统的哪一个实现。除生成子类的方法以外,另一种方法是用不同的子系统对象配置Facade对象。为定制facade,仅需对它的子系统对象(一个或多个)进行替换即可。
B、公共子系统类与私有子系统类:一个子系统与一个类的相似之处是,它们都有接口并且它们都封装了一些东西----类封装了状态和操作,而子系统封装了一些类。考虑一个类的公共和私有接口是有益的,我们也可以考虑子系统的公共和私有接口。子系统的公共接口包含所有的客户程序可以访问的类;私有接口仅用于对子系统进行扩充。当然,Facade类是公共接口的一部分,但它不是唯一的部分,子系统的其它部分通常也是公共的。私有化子系统类确实有用,但是很少有面向对象的编程语言支持这一点。
(6)、相关模式:AbstractFactory模式可以与Facade模式一起使用以提供一个接口,这一接口可用来以一种子系统独立的方式创建子系统对象。Abstract
Factory也可以代替Facade模式隐藏那些与平台相关的类。Mediator模式与Facade模式的相似之处是,它抽象了一些已有的类的功能。然而,Mediator的目的是对同事之间的任意通讯进行抽象,通常集中不属于任何单个对象的功能。Mediator的同事对象知道中介者并与它通信,而不是直接与其他同类对象通信。相对而言,Facade模式仅对子系统对象的接口进行抽象,从而使它们更容易使用;它并不定义新功能,子系统也不知道Facade的存在。通常来讲,仅需要一个Facade对象,因此Facade对象通常属于Singleton模式。
为子系统的一组接口提供一个一致的界面。使用户使用起来更加方便。
Facade模式在高层提供了一个统一的接口,解耦了系统。设计模式中还有另一种模式Mediator也和Facade有类似的地方。但是Mediator主要目的是对象间的访问的解耦(通讯时候的协议)。
示例代码1:
#include <iostream> #include <string> using namespace std; class SubSysOne { public: void MethodOne() { cout<<"方法一"<<endl; } }; class SubSysTwo { public: void MethodTwo() { cout<<"方法二"<<endl; } }; class SubSysThree { public: void MethodThree() { cout<<"方法三"<<endl; } }; //外观类 class Facade { private: SubSysOne* sub1; SubSysTwo* sub2; SubSysThree* sub3; public: Facade() { sub1 = new SubSysOne(); sub2 = new SubSysTwo(); sub3 = new SubSysThree(); } ~Facade() { delete sub1; delete sub2; delete sub3; } void FacadeMethod() { sub1->MethodOne(); sub2->MethodTwo(); sub3->MethodThree(); } }; //客户端 int main() { Facade* test = new Facade(); test->FacadeMethod(); /*result 方法一 方法二 方法三 */ return 0; } |
示例代码2:
Facade.h:
#ifndef _FACADE_H_ #define _FACADE_H_ class Subsystem1 { public: Subsystem1(); ~Subsystem1(); void Operation(); protected: private: }; class Subsystem2 { public: Subsystem2(); ~Subsystem2(); void Operation(); protected: private: }; class Facade { public: Facade(); ~Facade(); void OperationWrapper(); protected: private: Subsystem1* _subs1; Subsystem2* _subs2; }; #endif //~_FACADE_H_ |
Facade.cpp:
#include "Facade.h" #include <iostream> using namespace std; Subsystem1::Subsystem1() { } Subsystem1::~Subsystem1() { } void Subsystem1::Operation() { cout<<"Subsystem1 operation ..."<<endl; } Subsystem2::Subsystem2() { } Subsystem2::~Subsystem2() { } void Subsystem2::Operation() { cout<<"Subsystem2 operation ..."<<endl; } Facade::Facade() { this->_subs1 = new Subsystem1(); this->_subs2 = new Subsystem2(); } Facade::~Facade() { delete _subs1; delete _subs2; } void Facade::OperationWrapper() { this->_subs1->Operation(); this->_subs2->Operation(); } |
main.cpp:
#include "Facade.h" #include <iostream> using namespace std; int main() { Facade* f = new Facade(); f->OperationWrapper(); /*result Subsystem1 operation ... Subsystem2 operation ... */ return 0; } |
外观模式结构图:
设计模式之代理模式(Proxy)摘录
Proxy:
(1)、意图: 为其它对象提供一种代理以控制对这个对象的访问。
(2)、适用性:在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。
A、远程代理(Remote Proxy):为一个对象在不同的地址空间提供局部代表。
B、虚代理(Virtual Proxy):根据需要创建开销很大的对象。
C、保护代理(Protection Proxy):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
D、智能指针(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:a、对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它。b、当第一次引用一个持久对象时,将它装入内存。c、在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
(3)、相关模式:
A、适配器Adapter为它所适配的对象提供了一个不同的接口。相反,代理提供了与它的实体相同的接口。然而,用于访问保护的代理可能会拒绝执行实体会执行的操作,因此,它的接口实际上可能只是实体接口的一个子集。
B、尽管Decorator的实现部分与代理相似,但decorator的目的不一样。Decorator为对象添加一个或多个功能,而代理则控制对对象的访问。代理的实现与Decorator的实现类似,但是在相似的程度上有所差别。Protection
Proxy的实现可能与Decorator的实现差不多。另一方面,Remote Proxy不包含对实体的直接引用,而只是一个间接引用。Virtual
Proxy开始的时候使用一个间接引用,例如一个文件名,但最终将获取并使用一个直接引用。
远程代理:可以隐藏一个对象在不同地址空间的事实。
虚拟代理:通过代理来存放需要很长时间实例化的对象。
安全代理:用来控制真实对象的访问权限。
智能引用:当调用真实对象时,代理处理另外一些事。
Proxy模式的最大的好处就是实现了逻辑和实现的彻底解耦。
示例代码1:
#include <string> #include <iostream> using namespace std; //定义接口 class Interface { public: virtual void Request() = 0; }; //真实类 class RealClass : public Interface { public: virtual void Request() { cout<<"真实的请求"<<endl; } }; //代理类 class ProxyClass : public Interface { private: RealClass* m_realClass; public: virtual void Request() { m_realClass = new RealClass(); m_realClass->Request(); delete m_realClass; } }; //客户端 int main() { ProxyClass* test = new ProxyClass(); test->Request(); /*result 真实的请求 */ return 0; } |
示例代码2:
Proxy.h:
#ifndef _PROXY_H_ #define _PROXY_H_ class Subject { public: virtual ~Subject(); virtual void Request() = 0; protected: Subject(); private: }; class ConcreteSubject : public Subject { public: ConcreteSubject(); ~ConcreteSubject(); void Request(); protected: private: }; class Proxy { public: Proxy(); Proxy(Subject* sub); ~Proxy(); void Request(); protected: private: Subject* _sub; }; #endif//~_PROXY_H_ |
Proxy.cpp:
#include "Proxy.h" #include <iostream> using namespace std; Subject::Subject() { } Subject::~Subject() { } ConcreteSubject::ConcreteSubject() { } ConcreteSubject::~ConcreteSubject() { } void ConcreteSubject::Request() { cout<<"ConcreteSubject ... request ..."<<endl; } Proxy::Proxy() { } Proxy::Proxy(Subject* sub) { _sub = sub; } Proxy::~Proxy() { delete _sub; } void Proxy::Request() { cout<<"Proxy request ..."<<endl; _sub->Request(); } |
main.cpp:
#include "Proxy.h" #include <iostream> using namespace std; int main() { Subject* sub = new ConcreteSubject(); Proxy* p = new Proxy(sub); p->Request(); /*result Proxy request ... ConcreteSubject ... request ... */ return 0; }
|
代理模式结构图:
|