“接口隔离” 模式
- 在组织构建过程中,某些接口之间的直接依赖常常会带来很多问题、甚至根本无法实现。采用添加一层间接(稳定)接口,来隔离本来相互紧密关联的接口是一种常见的解决方案。
- 典型模式
- Facade
- Proxy
- Adapter
- Mediator
一、动机
系统间耦合的复杂度
上述A方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。
如何简化外部客户程序和系统间的交互接口,如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦成为面临的问题。
二、场景分析
例如有一个编程环境,它允许应用程序访问它的编译子系统。这个编译子系统包含了若干个类,如Scanner、Parser、ProgramNode、BytecodeStream和ProgramNodeBuilder,用于实现这一编译器。有些特殊的应用程序需要直接访问这些类,但是大多数编译器的用户并不关心语法分析和代码生成这样的细节;他们只是希望编译一些代码。对于这些用户,编译子系统中那些功能强大但层次较低的接口只会使他们的任务复杂化。
为了提供一个高层的接口并且对客户屏蔽这些类,编译子系统还包括一个Complier类。**这个类定义了一个编译器功能的统一接口。Complier类是一个外观,它给用户提供了一个单一而简单的编译子系统接口。**编译器的外观可方便大多数程序员使用,同时对少数懂得如何使用底层功能的人,它并不隐藏这些功能,如下图所示:
三、模式定义
为子系统中的一组接口提供一个一致(稳定)的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用(服用)。
门面系统中的角色:
- Facade门面角色:客户端可以调用这个角色的方法。此角色直销子系统的所有功能和责任。一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就说该角色没有实际的业务逻辑,只是一个委托类。
- subsystem子系统角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已。
何时使用门面模式:
- 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具有可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
- 当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间时相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。
优点:
-
它对客户端屏蔽子系统组件,因而减少了客户端处理的对象的数目并使得子系统用起来更加方便。
-
它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统组件的变化不会影响到客户端
在大型软件系统中降低编译依赖性至关重要,当子系统类改变时,希望尽量减少重编译工作以节省时间。使用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作。
四、结构
四、要点总结
- 从客户程序的角度来看,Facade模式简化了整个组件系统的接口,对于组件内部与外部的客户程序来说,达到了一种 “解藕” 的效果——内部子系统的任何变化不会影响到Facade接口的变化。
- Facade设计模式更注重从架构的层次看整个系统,而不是单个类的层次。Facade更多时候更是一种架构设计模式。