设计模式(15)-Facade Pattern(zz)

原文:http://www.cnblogs.com/zhenyulu/articles/55992.html


一、 门面(Facade)模式

外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。

医院的例子

用一个例子进行说明,如果把医院作为一个子系统,按照部门职能,这个系统可以划分为挂号、门诊、划价、化验、收费、取药等。看病的病人要与这些部门打交道,就如同一个子系统的客户端与一个子系统的各个类打交道一样,不是一件容易的事情。

首先病人必须先挂号,然后门诊。如果医生要求化验,病人必须首先划价,然后缴款,才能到化验部门做化验。化验后,再回到门诊室。

解决这种不便的方法便是引进门面模式。可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。这个接待员就是门面模式的体现,病人只接触接待员,由接待员负责与医院的各个部门打交道。

什么是门面模式

门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的门面(Facade)对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

就如同医院的接待员一样,门面模式的门面类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与门面对象打交道,而不需要与子系统内部的很多对象打交道。

二、 门面模式的结构

门面模式是对象的结构模式。门面模式没有一个一般化的类图描述,下图演示了一个门面模式的示意性对象图:



在这个对象图中,出现了两个角色:

门面(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。

子系统(subsystem)角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。

三、 门面模式的实现

一个系统可以有几个门面类

【GOF】的书中指出:在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。当然这并不意味着在整个系统里只能有一个门面类,而仅仅是说对每一个子系统只有一个门面类。或者说,如果一个系统有好几个子系统的话,每一个子系统有一个门面类,整个系统可以有数个门面类。

为子系统增加新行为

初学者往往以为通过继承一个门面类便可在子系统中加入新的行为,这是错误的。门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。

四、 在什么情况下使用门面模式

* 为一个复杂子系统提供一个简单接口
* 提高子系统的独立性
* 在层次化结构中,可以使用Facade模式定义系统中每一层的入口。


五、 一个例子

我们考察一个保安系统的例子,以说明门面模式的功效。一个保安系统由两个录像机、三个电灯、一个遥感器和一个警报器组成。保安系统的操作人员需要经常将这些仪器启动和关闭。

不使用门面模式的设计

首先,在不使用门面模式的情况下,操作这个保安系统的操作员必须直接操作所有的这些部件。下图所示就是在不使用门面模式的情况下系统的设计图。




可以看出,Client对象需要引用到所有的录像机(Camera)、电灯(Light)、感应器(Sensor)和警报器(Alarm)对象。代码如下:
using System;

public class Camera
{
public void TurnOn()
{
Console.WriteLine("Turning on the camera.");
}

public void TurnOff()
{
Console.WriteLine("Turning off the camera.");
}

public void Rotate(int degrees)
{
Console.WriteLine("Rotating the camera by {0} degrees.", degrees);
}
}

public class Light
{

public void TurnOff()
{
Console.WriteLine("Turning on the light.");
}

public void TurnOn()
{
Console.WriteLine("Turning off the light.");
}

public void ChangeBulb()
{
Console.WriteLine("changing the light-bulb.");
}
}

public class Sensor
{
public void Activate()
{
Console.WriteLine("Activating the sensor.");
}

public void Deactivate()
{
Console.WriteLine("Deactivating the sensor.");
}

public void Trigger()
{
Console.WriteLine("The sensor has triggered.");
}
}

public class Alarm
{

public void Activate()
{
Console.WriteLine("Activating the alarm.");
}

public void Deactivate()
{
Console.WriteLine("Deactivating the alarm.");
}

public void Ring()
{
Console.WriteLine("Ringing the alarm.");
}

public void StopRing()
{
Console.WriteLine("Stop the alarm.");
}
}

public class Client
{
private static Camera camera1, camera2;
private static Light light1, light2, light3;
private static Sensor sensor;
private static Alarm alarm;

static Client()
{
camera1 = new Camera();
camera2 = new Camera();
light1 = new Light();
light2 = new Light();
light3 = new Light();
sensor = new Sensor();
alarm = new Alarm();
}

public static void Main( string[] args )
{
camera1.TurnOn();
camera2.TurnOn();
light1.TurnOn();
light2.TurnOn();
light3.TurnOn();
sensor.Activate();
alarm.Activate();
}
}


六、 使用门面模式的设计

一个合情合理的改进方法就是准备一个系统的控制台,作为保安系统的用户界面。如下图所示:



程序代码如下:
using System;

public class Camera
{
public void TurnOn()
{
Console.WriteLine("Turning on the camera.");
}

public void TurnOff()
{
Console.WriteLine("Turning off the camera.");
}

public void Rotate(int degrees)
{
Console.WriteLine("Rotating the camera by {0} degrees.", degrees);
}
}

public class Light
{

public void TurnOff()
{
Console.WriteLine("Turning on the light.");
}

public void TurnOn()
{
Console.WriteLine("Turning off the light.");
}

public void ChangeBulb()
{
Console.WriteLine("changing the light-bulb.");
}
}

public class Sensor
{
public void Activate()
{
Console.WriteLine("Activating the sensor.");
}

public void Deactivate()
{
Console.WriteLine("Deactivating the sensor.");
}

public void Trigger()
{
Console.WriteLine("The sensor has triggered.");
}
}

public class Alarm
{

public void Activate()
{
Console.WriteLine("Activating the alarm.");
}

public void Deactivate()
{
Console.WriteLine("Deactivating the alarm.");
}

public void Ring()
{
Console.WriteLine("Ringing the alarm.");
}

public void StopRing()
{
Console.WriteLine("Stop the alarm.");
}
}

public class SecurityFacade
{
private static Camera camera1, camera2;
private static Light light1, light2, light3;
private static Sensor sensor;
private static Alarm alarm;

static SecurityFacade()
{
camera1 = new Camera();
camera2 = new Camera();
light1 = new Light();
light2 = new Light();
light3 = new Light();
sensor = new Sensor();
alarm = new 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();
}
}

public class Client
{
private static SecurityFacade security;

public static void Main( string[] args )
{
security = new SecurityFacade();
security.Activate();
Console.WriteLine("\n--------------------\n");
security.Deactivate();
}
}



参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社
posted on 2004-10-24 00:13 吕震宇 阅读(6640) 评论(10) 编辑 收藏 引用 网摘 所属分类: 设计模式

评论
# re: 设计模式(15)-Facade Pattern 2004-10-25 09:09 HiRong
通过这个例子我只看到你将复杂度从一个类移到另一个类而已,并不能看到Facade Pattern的好处。如果再增加一个对象,比如说后勤人员可以控制一些灯的开和关,这时才能体现出Facade Pattern的用途。 回复 更多评论


# re: 设计模式(15)-Facade Pattern 2004-10-25 09:36 lichdr
還是能看到好處的,就是寫前端的人不用管後端的事,它只跟那個facade打交道就行了。前後端隔離了

當然前後端一個人干的就沒只是把複雜度從一個類到另 一個類而已了。 回复 更多评论


# re: 设计模式(15)-Facade Pattern 2004-11-17 17:28 luoluo
这个例子客户端需要调用服务来做的事情的流程 不是很复杂

医院的例子更好一些 病人要看病 需要做一系列的事情 比较复杂

facade就显得很方便 回复 更多评论


# re: 设计模式(15)-Facade Pattern 2005-08-01 10:00 BigHead
如果有很多Client这就体现出好处,可以试想下,如果Camera Light Sensor Alarm这几个类的实现改变了导致使用类也要改变的话,直接修改SecurityFacade就可以了.前提是这些改变不会导致连 SecurityFacade的接口也要改变.这就给维护带来了很好的简单性,这也就是松耦合带来的好处了.


facade模式的其他相关内容:
1.谁能给我解释下Facade模式???
http://www.javanb.com/j2ee/1/10508.html
我来举例子帮你说明:

1)、假设你有一个类,里面分别提供了对某表的insert,update,delete,select方法。如果人家要对此表操作,就调用你这个类。可是你想这么做:对于那些高安全性的开发者,你可以给整个类的各种方法。可是对那些低安全性的开发者(比如第三方合作者),就只给select方法。
于是你再做了一个类,只有select方法(其实就是调用前面那个类的select),把这个facade类开发给低安全性开发者。这就是facade的第一个作用:隐藏

2)、假设你有多个类,分别管理多表的操作。现在有个需求,可能一个事务涉及到多表的操作(比如用户登录,先要在用户表验证密码,然后再到登录日志表记一笔),那么你可以做一个facade,把这一系列的操作封装成一个方法。人家不用跟底层的单表打交道,只简单调用你的facade的方法就OK。这就是 facade的第二个作用:封装

其他的作用我不清楚,我也没用过。但就上面这2个作用,让你有充分的理由用FACADE。

2.设计模式之Facade(外观 总管 Manager)
http://java.ccidnet.com/art/3741/20040325/542091_1.html

Facade模式的定义: 为子系统中的一组接口提供一个一致的界面.
Facade一个典型应用就是数据库JDBC的应用.

3.关于JDBC facade 的疑问
http://www.jdon.com/jive/thread.jsp;jsessionid=8C27EB638A4561796FB7BF7DC68CDD07?forum=91&thread=6316
一个facade 要这样
private static ConnectionManager connManager = null;
private Connection conn = null;
private Statement stmt = null;
private PreparedStatement prepstmt = null;
private CallableStatement callstmt = null;


可能还有
private ResultSet rs = null;
private ResultSetMetaData rsmd = null;

实现的一个类是很大的,而且每次调用都要new facade
这样是否有问题?

我的意思是说 每次都生成这样大的一个对象,是不是很慢?


re: 当然 你使用singleton
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值