初探外观模式
代码链接
koonchen/design-patterns/facade
要点
为子系统中的一组接口提供一个一致的界面, Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
假设我们拥有一个编程器,这个编译器包含一些类,比如: Scanner 、 Parser 、 ProgramNode 、 BytecodeStream 和 ProgramNodeBuilder 等,用于实现编译器。大多数的用户仅仅将使用编译器完成编译工作,子系统中那些功能强大但层次较低的接口只会让他们将任务复杂化。
现在,我们用一个 Compiler 类来定义这个编译器的统一接口,它是一个外观,给用户提供了一个统一而简单的编译器子系统接口。这方便了大多数人使用,同时也对懂得使用底层功能的人展示它的底层功能。
什么情况下适用外观模式:
- 当我们要为一个复杂子系统提供一个简单接口的时候:子系统往往因为不断演化而变得越来越复杂。这给那些不需要定制子系统的用户适用上造成困难,而 Facade 可以提供一个简单的缺省视图,这一视图对大多数用户而言已经足够,而需要定制的用户则可以通过 Facade 层来使用子系统。
- 客户程序与抽象类的实现之间存在很大的依赖性:引入 Facade 将这个子系统与客户以及其他的子系统进行分离,可以提高子系统的独立性和可移植性。
- 使用 Facade 作为子系统的入口:如果子系统之间相互通讯,那么 Facade 可以简化它们的依赖关系。
Facade 模式的参与者:
- Facade ( Compiler ) : 知道哪些子系统负责处理请求,将用户的请求恰当发送。
- Subsystem classes ( Scanner 等 ):实现子系统的功能,处理 Facade 指派。
PS: 没有从子系统指向 Facade 的指针。
该系统的结构如下:
从协作角度出发,我们可以这样理解这个系统:
- 客户程序通过发送请求给 Facade 的方式与子系统通讯, Facade 将这些消息转发给适当的子系统对象。
- 使用 Facade 的客户程序不需要直接直接访问子系统对象。
Facade 模式具有以下优点:
- 它对客户屏蔽子系统组件,因为减少了客户处理的对象的数目并使得子系统使用起来更加方便。
- 它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的,松耦合关系使得子系统的组件变化不会影响到它的客户。 Facade 模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。
- 如果应用需要,它并不限制它们使用子系统。因此我们可以在系统易用性和通用性之间加以选择。
实现
在实现上,我们需要注意以下几点:
- 降低客户 - 子系统之间的耦合度:用抽象类实现 Facade 而它的具体子类对应于不同的子系统实现,这可以进一步降低客户与子系统的耦合度。现在,客户可以通过抽象的 Facade 类接口与子系统通讯。
- 公共子系统类与私有子系统类:一个子系统与一个类的相似之处在于,他们都有接口并且他们都封装了一些东西——类封装了状态和操作,而子系统封装了一些类。
java 实现
1 | import java.util.List; |
facade 在这里的实现就是一个子系统的入口。
python 实现
1 | #!/usr/bin/env python |
实现大同小异。
PS: 妥协了,从上一章开始,就改用 pyhton 的四格缩进了…
Abstract Factory 模式可以与 Facade 模式一起使用以提供一个接口,这一个接口可用来与一种子系统独立地方式创建子系统对象。当然, Abstract Factory 也可以代替 Facade 来隐藏那些平台相关的类,就是还需要管理子类,更显复杂。
Mediator 模式还没有开始,它与 Facade 相似的地方是,它抽象了一些已有的类的功能。然而 Mediator 的目的是对同事之间的任意通讯进行抽象,通常集中不属于任何单个对象的功能。它的同事知道中介者,并与其通讯。而 Facade 模式仅对子系统的接口进行抽象,它不会定义新的功能,子系统也不知道 Facade 的存在。
通常,只有一个 Facade 对象,所以它属于 Singleton 模式。