外部与一个子系统的通信必须通过一个统一的门面对象进行就是门面模式。
1. 什么是门面模式
门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的门面(Facade)对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
门面模式没有一个一般化的类图描述,最好的描述方法实际上就是以一个例子说明。如下:
涉及的角色有两个:
门面(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统中。
子系统(SubSystem)角色:可以同时有一个或多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个客户端都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。
2. 门面模式的实现
门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,所以建议使用单例模式。并不是每个系统只有一个门面类,而是每一个子系统都有一个门面类。
如果向子系统增加新的行为,初学者的做法是通过继承门面类。这样的做法是错误的,门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。
保安系统的例子:
一个保安系统由两个录像机、三个点灯、一个遥感器和一个报警器组成。保安系统的操作人员需要经常将这些仪器启动和关闭。首先,在不使用门面模式的情况下,操作这个保安系统的操作员必须直接操作所有的这些部件。
(1)不使用门面模式:
设计图:
可以看出,客户端需要引用录像机、灯光、感应器、和报警器对象。而且Client对象必须对保安系统全部了解。
代码如下:
package cn.qlq.facade; public class Camera { public void turnOn() { System.out.println("打开相机"); } public void turnOff() { System.out.println("关闭相机"); } public void rotate() { System.out.println("旋转相机"); } }
package cn.qlq.facade; public class Light { public void turnOn() { System.out.println("打开灯光"); } public void turnOff() { System.out.println("关闭灯光"); } public void changeBulb() { System.out.println("更换灯光"); } }
package cn.qlq.facade; public class Sensor { public void activate() { System.out.println("激活传感器"); } public void deactivate() { System.out.println("关闭传感器"); } public void trigger() { System.out.println("触发传感器"); } }
package cn.qlq.facade; public class Alarm { public void activate() { System.out.println("激活警报器"); } public void deactivate() { System.out.println("关闭警报器"); } public void ring() { System.out.println("拉响警报器"); } public void stopRing() { System.out.println("关闭警报器"); } }
客户端代码:
package cn.qlq.facade; public class Client { private static Camera camera1 = new Camera(); private static Camera camera2 = new Camera(); private static Light light1 = new Light(); private static Light light2 = new Light(); private static Light light3 = new Light(); private static Alarm alarm = new Alarm(); private static Sensor sensor = new Sensor(); public static void main(String[] args) { camera1.turnOn(); camera2.turnOn(); light1.turnOn(); light2.turnOn(); light3.turnOn(); alarm.activate(); sensor.activate(); } }
(2)使用门面模式
改进办法就是准备一个系统的控制台,作为保安系统的用户界面。用户只需要操作这个简单的界面就可以操作所有的内部仪器,这就是门面模式。
设计图如下:
代码:
增加的门面类如下:
package cn.qlq.facade; public class SecurityFacade { private static Camera camera1 = new Camera(); private static Camera camera2 = new Camera(); private static Light light1 = new Light(); private static Light light2 = new Light(); private static Light light3 = new Light(); private static Alarm alarm = new Alarm(); private static Sensor sensor = new Sensor(); public void active() { camera1.turnOn(); camera2.turnOn(); light1.turnOn(); light2.turnOn(); light3.turnOn(); alarm.activate(); sensor.activate(); } public void deactive() { camera1.turnOff(); camera2.turnOff(); light1.turnOff(); light2.turnOff(); light3.turnOff(); alarm.deactivate(); sensor.deactivate(); } }
客户端代码:
package cn.qlq.facade; public class Client { public static void main(String[] args) { SecurityFacade facade = new SecurityFacade(); facade.active(); } }
在J2EE中,Session用到了门面模式。