目的
Facade是结构模式的一种,它让你可以为一个复杂的系统,类库或者框架提供一个简单的接口。
问题
想象一下,代码必须和一大堆复杂的框架或者类库协作。你必须手动实力话这些对象,跟踪依赖,正确的顺序关系等等。
最后,你的业务逻辑类会和第三方类库的实现紧密耦合。这些代码难以理解和维护。
解决
门面是一个类,它为一个包含很多类的复杂子系统提供一个简单的接口。相对直接调用子系统而言,门面提供有限的功能。它仅提供客户端关心的那些特性。
当你在使用一个拥有很多模块的的复杂类库,但是你只用到其中一部分功能时,使用门面模式就显得很便利。
比如,一个上传短视频到Youtube伤的app使用了一个专业的视频转换类库。但是它真正需要的只是一个拥有encode(filename,format)方法的类。创建这种类之后,你变有了第一个门面。
现实世界的类比
电话下单
当你用电话向一个商店下单时,话务员就是所有服务和部门的门面。他或者她提供了下单,支付,配送的简单接口。
结构
Facade(门面)为访问子系统的特定功能提供方便。它知道怎样引导客户的请求和怎样为所有moving parts做准备。
Additional facades用来隔离功能和阻止源门面变成另外一个复杂结构。Additional facades也可以被客户端或者其他门面使用。
Complex subsystem(复杂的子系统)包含很多类。为了让他们做一些有意义的事情,你必须知道它的实现细节,初始化顺序等很多事情。
注意:子系统并不关心门面的存在,它直接和其他模块协作。Client使用门面代替直接调用子系统对象。
伪代码
在这个例子中,门面简化了和一个复杂视频转换框架的协作。
门面是一个单独的类,它提供一个公开的方法来处理框架复杂的配置并返回一个正确的格式。
通过这种方式,门面模式保证客户端代码简单、干净、可靠。
1 | // Some classes of a complex 3rd-party video conversion framework. We don't |
适用性
当你需要一个简单但是功能有限的复杂子系统接口时
通常,子系统随着时间的推移变得越来越复杂。即使使用了设计模式也难避免创建更多的类。子系统可能变的更加灵活并且在不同的环境中复用性更高,但是它的样板代码数量也会随之增长。门面模式尝试通过提供访问子系统的一部分来适应更多客户端的需要。当你想把一个子系统构建成层
创建门面来定义每个层子系统的连接点。如果多子系统之间相互依赖,你可以通过要求子系统只能通过门面交互来限制耦合。
如何实现
检查是否可以使用简化的接口和一个复杂的子系统交互。
如果接口使客户端没有子系统的依赖,你就在正确的轨道上。创建一个门面类并在接口中描述它。它必须能够引导客户端调用适当的子系统对象。门面应该关心子系统正确的初始化。通常,这些代码在门面的构造方法中,懒实例化往往比较有用。
如果客户端仅和门面协作,你将得到巨大的收益。在这种情况下,客户端不需要关心子系统代码的变化。比如,当一个库的代码更新世,你只需要修改门面。
如果这个门面变的太大,请考虑抽离出一个新的门面。
优点
分离客户端和子系统组件。
客户端代码和子系统最小耦合。
缺点
- 门面可能造成god object,它和所有应用类耦合。
和其他模式的关系
Facade重新定义了一个接口,而Adapter重用了一个老接口。记住,Adapter使两个已存在接口协作,反对完全重新定义一个接口。
Abstract Factory可以用来替代Facade来隐藏平台特定的类。
Flyweight展示如何制造更多小对象,而Facade展示如何使用一个对象代表整个子系统。
Meditor在抽象已存在类的功能上和Facade很像。Mediator抽象/集中两个随意交互的协作对象。它常规的做法是“add values”,并且协作对象间相互知道被引用。相比之下,Facade为子系统定义了一个简单的接口,它并不添加新功能,并且子系统类不知道它的存在。
Facade可以被改造成Singleton,因为大多情况下单例门面对象就够了。
Facade在缓冲一个复杂实体和初始化这点上和Proxy很像。不像Facade,Proxy模式和他服务的对象拥有相同的接口,使得它们是通用的。
Java中模式的使用
用例:在用Java写的app中,门面模式很常见。它特别用来处理和复杂类库和API协作的情景。
鉴定:Facade可以在具有简单接口的类中被识别,但是它将大部分工作委托给其他类。通常,门面管理它们使用对象的生命周期。