一、 門(mén)面(Facade)模式
外部與一個(gè)子系統的通信必須通過(guò)一個(gè)統一的門(mén)面(Facade)對象進(jìn)行,這就是門(mén)面模式。
醫院的例子
用一個(gè)例子進(jìn)行說(shuō)明,如果把醫院作為一個(gè)子系統,按照部門(mén)職能,這個(gè)系統可以劃分為掛號、門(mén)診、劃價(jià)、化驗、收費、取藥等??床〉牟∪艘c這些部門(mén)打交道,就如同一個(gè)子系統的客戶(hù)端與一個(gè)子系統的各個(gè)類(lèi)打交道一樣,不是一件容易的事情。
首先病人必須先掛號,然后門(mén)診。如果醫生要求化驗,病人必須首先劃價(jià),然后繳款,才能到化驗部門(mén)做化驗?;灪?,再回到門(mén)診室。
解決這種不便的方法便是引進(jìn)門(mén)面模式??梢栽O置一個(gè)接待員的位置,由接待員負責代為掛號、劃價(jià)、繳費、取藥等。這個(gè)接待員就是門(mén)面模式的體現,病人只接觸接待員,由接待員負責與醫院的各個(gè)部門(mén)打交道。
什么是門(mén)面模式
門(mén)面模式要求一個(gè)子系統的外部與其內部的通信必須通過(guò)一個(gè)統一的門(mén)面(Facade)對象進(jìn)行。門(mén)面模式提供一個(gè)高層次的接口,使得子系統更易于使用。
就如同醫院的接待員一樣,門(mén)面模式的門(mén)面類(lèi)將客戶(hù)端與子系統的內部復雜性分隔開(kāi),使得客戶(hù)端只需要與門(mén)面對象打交道,而不需要與子系統內部的很多對象打交道。
二、 門(mén)面模式的結構
門(mén)面模式是對象的結構模式。門(mén)面模式?jīng)]有一個(gè)一般化的類(lèi)圖描述,下圖演示了一個(gè)門(mén)面模式的示意性對象圖:
在這個(gè)對象圖中,出現了兩個(gè)角色:
門(mén)面(Facade)角色:客戶(hù)端可以調用這個(gè)角色的方法。此角色知曉相關(guān)的(一個(gè)或者多個(gè))子系統的功能和責任。在正常情況下,本角色會(huì )將所有從客戶(hù)端發(fā)來(lái)的請求委派到相應的子系統去。
子系統(subsystem)角色:可以同時(shí)有一個(gè)或者多個(gè)子系統。每一個(gè)子系統都不是一個(gè)單獨的類(lèi),而是一個(gè)類(lèi)的集合。每一個(gè)子系統都可以被客戶(hù)端直接調用,或者被門(mén)面角色調用。子系統并不知道門(mén)面的存在,對于子系統而言,門(mén)面僅僅是另外一個(gè)客戶(hù)端而已。
三、 門(mén)面模式的實(shí)現
一個(gè)系統可以有幾個(gè)門(mén)面類(lèi)
【GOF】的書(shū)中指出:在門(mén)面模式中,通常只需要一個(gè)門(mén)面類(lèi),并且此門(mén)面類(lèi)只有一個(gè)實(shí)例,換言之它是一個(gè)單例類(lèi)。當然這并不意味著(zhù)在整個(gè)系統里只能有一個(gè)門(mén)面類(lèi),而僅僅是說(shuō)對每一個(gè)子系統只有一個(gè)門(mén)面類(lèi)?;蛘哒f(shuō),如果一個(gè)系統有好幾個(gè)子系統的話(huà),每一個(gè)子系統有一個(gè)門(mén)面類(lèi),整個(gè)系統可以有數個(gè)門(mén)面類(lèi)。
為子系統增加新行為
初學(xué)者往往以為通過(guò)繼承一個(gè)門(mén)面類(lèi)便可在子系統中加入新的行為,這是錯誤的。門(mén)面模式的用意是為子系統提供一個(gè)集中化和簡(jiǎn)化的溝通管道,而不能向子系統加入新的行為。
四、 在什么情況下使用門(mén)面模式
- 為一個(gè)復雜子系統提供一個(gè)簡(jiǎn)單接口
- 提高子系統的獨立性
- 在層次化結構中,可以使用Facade模式定義系統中每一層的入口。
五、 一個(gè)例子
我們考察一個(gè)保安系統的例子,以說(shuō)明門(mén)面模式的功效。一個(gè)保安系統由兩個(gè)錄像機、三個(gè)電燈、一個(gè)遙感器和一個(gè)警報器組成。保安系統的操作人員需要經(jīng)常將這些儀器啟動(dòng)和關(guān)閉。
不使用門(mén)面模式的設計
首先,在不使用門(mén)面模式的情況下,操作這個(gè)保安系統的操作員必須直接操作所有的這些部件。下圖所示就是在不使用門(mén)面模式的情況下系統的設計圖。
可以看出,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();
}
}
六、 使用門(mén)面模式的設計
一個(gè)合情合理的改進(jìn)方法就是準備一個(gè)系統的控制臺,作為保安系統的用戶(hù)界面。如下圖所示:
程序代碼如下:
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();
}
}