外观模式(Facade Pattern)
定义
定义了一个高层接口,该接口为子系统中的一组接口提供一个一致的界面,使得这一子系统更加容易使用。
常用场景
- 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变的越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具有可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。外观模式可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层;
- 当客户程序与抽象类的实现部分之间存在很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性;
- 当需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,我们就可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。
优点
- 松散耦合
- 外观模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。即要点2.
- 简单易用
- 外观模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观交互就可以了,相当于外观类为外部客户端使用子系统提供了一站式服务。
- 更好的划分访问层次
- 通过合理使用Facade,可以帮助我们更好的划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好的隐藏了内部的细节。
缺点
过多的或者是不太合理的Facade也容易让人迷惑,到底是调用Facade好呢,还是直接调用模块好
C++实现
举例:手机
手机本身对我们来说就是一个外观系统。手机内部有开关机、照相、下载、删除、打接电话、收发信息等功能,每个功能都是一个子系统。对于我们来说,不需要清楚地知道每个子系统的运行原理,只需要点击屏幕上的相关按钮即可完成操作,系统内部会完成相关的调用。
类图:
- Facade:知道哪些子系统类负责处理请求,并且将客户的请求代理给适当的子系统对象;
- SubSystem:实现子系统具体的功能;处理由Facade对象指派的任务;但是,SubSystem没有Facade的任何相关信息,也就是说,没有指向Facade的指针。
- Client:通过发送请求给Facade的方式与子系统进行通信,而不直接与子系统打交道,Facade将这些消息转发给适当的子系统对象。尽管是子系统中的有关对象在做实际工作,但Facade模式本身也必须将它的接口转换成子系统的接口,这里是不是有点适配器模式的感觉呢?这就是学习结构型设计模式的感觉,感觉都很相似,但是仔细的去研究时,就会发现各自的用处。
代码:
#include <iostream>
#include <string>
using std::cout;
using std::endl;
// 开关机系统
class OnOffSystem
{
public:
void On()
{
std::cout << "手机开机." << std::endl;
}
void Off()
{
std::cout << "手机关机." << std::endl;
}
};
// 照相系统
class PhotoSystem
{
public:
void Photo()
{
std::cout << "拍照." << std::endl;
}
void Viedo()
{
std::cout << "录制视频." << std::endl;
}
};
// 打接电话系统
class CallSystem
{
public:
void Call()
{
std::cout << "打电话." << std::endl;
}
void Pick()
{
std::cout << "接电话." << std::endl;
}
};
class Phone
{
public:
Phone() : m_onOffSystem(nullptr), m_photoSystem(nullptr), m_callSystem(nullptr)
{
}
void SetOnOff(OnOffSystem* system)
{
m_onOffSystem = system;
}
void SetPhoto(PhotoSystem* system)
{
m_photoSystem = system;
}
void SetCall(CallSystem* system)
{
m_callSystem = system;
}
void On()
{
if (m_onOffSystem)
m_onOffSystem->On();
}
void Off()
{
if (m_onOffSystem)
m_onOffSystem->Off();
}
void Photo()
{
if (m_photoSystem)
m_photoSystem->Photo();
}
void Vedio()
{
if (m_photoSystem)
m_photoSystem->Viedo();
}
void Call()
{
if (m_callSystem)
m_callSystem->Call();
}
void Pick()
{
if (m_callSystem)
m_callSystem->Pick();
}
private:
OnOffSystem* m_onOffSystem; // 外部引用,不需释放
PhotoSystem* m_photoSystem; // 按需装载, 可以没有,功能也没有
CallSystem* m_callSystem;
};
int FacadeTest(int argc, char** argv)
{
Phone* pFacade = new Phone;
OnOffSystem* pOnOffSystem = new OnOffSystem;
PhotoSystem* pPhotoSystem = new PhotoSystem;
CallSystem* pCallSystem = new CallSystem;
pFacade->SetOnOff(pOnOffSystem);
//pFacade->SetPhoto(pPhotoSystem); // 不装载此功能
pFacade->SetCall(pCallSystem);
pFacade->On();
pFacade->Photo();
pFacade->Photo();
pFacade->Vedio();
pFacade->Call();
pFacade->Call();
pFacade->Pick();
pFacade->Off();
delete pCallSystem;
delete pPhotoSystem;
delete pOnOffSystem;
delete pFacade;
return 0;
}