C#面向对象设计模式纵横谈:Facade 外观模式
系统的复杂度
假设我们需要开发一个坦克模拟系统用于模拟坦克车在各种作战环境中的行为,其中坦克系统由引擎、控制器、车轮、车身等各子系统构成。
如何使用这样的系统
动机(Motivation)
上述A方案的问题在于组件的客户(即外部接口,或客户程序)和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?
意图(Intent)
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
——《设计模式》GoF
例说Facade应用
以前面的例子为例
我们所说的接口其实并不一定是Interface,只要是Public方法,能被外部调用的方法都叫接口,这里的定义其实是更加广义的接口定义,即露在外面和外界所交互的这一部分。这里主系统和子系统之间的关系不是继承关系,而应该是一种包含的关系。
这样在外部使用的时候只能使用TankFacade类和里面的Start、Stop等方法,其他子系统都被包含在内部了。这样减轻了使用的复杂度,客户程序只用关心TankFacade,而不用关心里面的子系统情况。更重要的是,这样的设计有效地把客户程序和子系统解耦。
结构(Structure)
这种结构不仅体现了类的单一职责原则,而且也体现了开放封闭原则。而且子系统和系统之间是个组合关系,而不是继承关系。高层总是相对稳定,低层总是相对易变。所以我们应该尽量依赖高层抽象,而不是低层细节实现。
Facade模式的几个要点
从客户程序的角度来看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。
Facade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。
注意区分Facade模式、Adapter模式、Bridge模式与Decorator模式:
Facade模式注重简化接口
Adapter模式注重转换接口
Bridge模式注重分离接口(抽象)与其实现
Decorator模式注重稳定接口的前提下为对象扩展功能
.NET架构中的Facade应用
假如我们做一个网上购物系统,考虑它的认证系统。用户权限不同,能做的事情也不同,它可能会调用各种各样的子系统。认证系统里面也可能包含很多子系统,比如第三方认证等等。这些认证子系统合作起来丰富了我们网站的功能,那么这种情况我们就可以考虑把认证的各个子系统封装成一个认证系统。
如果我们想做跨平台的及时聊天工具,我们也可以用一个Facade封装某个平台系统的API接口。这样我们在使用API的时候,就不需要去关心平台内部的变化。