门面模式是对象的结构模式。
外部与一个子系统的通信必须通过一个统一的门面对象进行,这就是门面模式。
什么是门面模式
门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的门面对象进行。
门面模式提供一个高层次的接口,使得子系统更易于使用。
门面模式的结构
在这个对象图中,出现了两个角色:
- 门面角色(Facade): 客户端可以调用这个角色的方法。此角色知晓相关的(一个或多个)子系统的的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
- 子系统角色(Subsystem): 可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另一个客户端而已。
门面模式的实现
一个系统可以有几个门面类:
在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,也就是说,它是一个单例类。
但这并不意味着在整个系统里只能有一个门面类,而仅仅是说,对每一个子系统只有一个门面类。
或者说,如果一个系统有好几个子系统的话,每一个子系统有一个门面类,整个系统可以有数个门面类。
以医院为例,可以为每一个不同的科室配备不同的接待员类。
为子系统增加新行为:
初学者往往以为通过继承一个门面类便可以在系统中加入新的行为,这是错误的。
门面模式的用意是,为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。
仍以医院为例,接待员并不是医护人员,接待员并不能为病人提供医疗服务。
在什么情况下使用门面模式
为一个复杂子系统提供一个简单接口
子系统往往因为不断演化而变的越来越复杂,使用门面模式可以使得子系统更具有可复用性。
Facade模式可以提供一个简单的默认视图,对大多数用户来说这个视图已经足够用了,
而那些需要进一步继承的用户可以越过Facade层直接对子系统进行继承。
子系统的独立性
一般而言,子系统和其他子系统之间、客户端与实现化层之间存在着很大的依赖性。
引入Facade模式将一个子系统与它的客户端及其他子系统分离,可以提高子系统的独立性和可移植性。
层次化结构
在构建一个层次化的系统时,可以使用 Facade模式定义系统中每一层的入口。如果层与层之间是相互依赖的,
则可以限定它们仅通过Facade进行通信,从而简化层与层之间的依赖关系。
一个例子
这里从代码重构的角度演示门面模式的应用。
这里给出一个保安系统,首先给出一个系统不适用门面模式的解决方案,然后指出其缺点,再将门面模式引入,并对源代码进行改组重构。
一个保安系统由两个录像机、三个电灯、一个遥感器和一个报警器组成。保安系统的操作人员需要经常将这些仪器启动和关闭。
不使用门面模式的设计
代码清单:
客户端角色
public class Client { static private Camera camera1,camera2; static private Light light1,light2,light3; static private Sensor sensor; static private Alarm alarm; public static void main(String[] args) { // TODO Auto-generated method stub camera1.turnOn(); camera2.turnOn(); light1.turnOn(); light2.turnOn(); light3.turnOn(); sensor.activate(); alarm.activate(); } }
Camera
public class Camera { public void turnOn(){ System.out.println("Turning on the camera."); } public void turnOff(){ System.out.println("Turning off the camera"); } public void rotate(int degrees){ System.out.println("rotating the camera by" + degrees + " degrees."); } }
Light
public class Light { public void turnOn() { System.out.println("Turning on the light."); } public void turnOff(){ System.out.println("Turning off the light."); } public void changeBulb(){ System.out.println("changing the light-bulb."); } }
Sensor
public class Sensor { public void activate(){ System.out.println("Activating the sensor."); } public void deactivate(){ System.out.println("Deactivating the sensor."); } public void trigger(){ System.out.println("The sensor has been triggered."); } }
Alarm
public class Alarm { public void activate(){ System.out.println("Activating the alarm."); } public void deactivate(){ System.out.println("deactivating the alarm."); } public void ring() { System.out.println("Ringing the alarm."); } public void stopRing(){ System.out.println("Stop the alarm."); } }
使用门面模式的设计
一个合情合理的改进方法是准备一个系统的控制台,作为保安系统的用户界面。
用户只需要操作这个简化的界面就可以操控所有的内部仪器,这实际上就是门面模式的用意。
可以看出,门面SecurityFacade 对象承担了与保安系统内部各个对象打交道的任务,客户端对象只需要与门面对象打交道即可。
客户端
public class Client { private static SecurityFacade security; public static void main(String[] args) { // TODO Auto-generated method stub security.activate(); } }
门面类 SecurityFacade
public class SecurityFacade { private Camera camera1,camera2; private Light light1,light2,light3; private Sensor sensor; private Alarm alarm; public void activate(){ camera1.turnOn(); camera2.turnOn(); light1.turnOn(); light2.turnOn(); light3.turnOn(); sensor.activate(); alarm.activate(); } public void deactivate(){ camera1.turnOff(); camera2.turnOff(); light1.turnOff(); light2.turnOff(); light3.turnOff(); sensor.deactivate(); alarm.deactivate(); } }
其他Camera,Light, Sensor, Alarm类与改进前相同。
Session门面模式
Session门面模式是J2EE模式的一种,实际上也是门面模式在J2EE框架中的应用。
什么是Session门面模式
Session门面模式用一个SessionBean作为门面,封装一个工作流程中的商务对象之间的相互作用。
Session门面对象管理商务对象并为客户端提供一个粗粒度的服务层。
Session门面模式的结构