意圖
為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
場景
在一個為游戲充值的網站中,創建訂單需要與三個外部接口打交道:
l 用戶系統:根據用戶名獲取用戶ID、查看用戶是否已經激活了游戲
l 卡系統:查看某種類型的充值卡是否還有庫存
l 充值系統:創建一個訂單,並且返回訂單號
如果直接讓網站和三個外部接口發生耦合,那麼網站因為外部系統接口修改而修改的概率就很大了,並且就這些小接口來說並不是十分友善,它們提供的大多數是工具方法,具體怎麼去使用還是要看充值網站創建訂單的邏輯。
Facade的思想就是在小接口上封裝一個高層接口,屏蔽子接口的調用,提供外部更簡潔,更易用的接口。
示例代碼
using System;
using System.Collections.Generic;
using System.Text;
namespace FacadeExample
{
class Program
{
static void Main(string[] args)
{
PayFacacde pf = new PayFacacde();
Console.WriteLine("order:" + pf.CreateOrder("yzhu", 0, 1, 12) + " created");
}
}
class PayFacacde
{
private AccountSystem account = new AccountSystem();
private CardSystem card = new CardSystem();
private PaySystem pay = new PaySystem();
public string CreateOrder(string userName, int cardID, int cardCount, int areaID)
{
int userID = account.GetUserIDByUserName(userName);
if (userID == 0)
return string.Empty;
if (!account.UserIsActived(userID, areaID))
return string.Empty;
if (!card.CardHasStock(cardID, cardCount))
return string.Empty;
return pay.CreateOrder(userID, cardID, cardCount);
}
}
class AccountSystem
{
public bool UserIsActived(int userID, int areaID)
{
return true;
}
public int GetUserIDByUserName(string userName)
{
return 123;
}
}
class CardSystem
{
public bool CardHasStock(int cardID, int cardCount)
{
return true;
}
}
class PaySystem
{
public string CreateOrder(int userID, int cardID, int cardCount)
{
return "0000000001";
}
}
}
代碼說明
l PayFacade類就是門面類型,提供給客戶端調用,它本身調用子接口。可以看到,創建一個訂單首先要根據用戶名獲取用戶ID、然後要看用戶是否已經激活了游戲、然後看充值卡是否有庫存,最後才是創建訂單。
l AccountSystem、CardSystem以及PaySystem就是子接口,它們提供了賬戶、卡以及充值相關的一些接口方法。
l Facade模式太常用了,把和多方關聯的邏輯代碼再進行一次封裝,提供一個高層接口就是Facade的思想。比如在做論壇程序的時候,一些操作需要調用權限訪問模塊(發帖、管理帖子),另外一些操作可以直接調用(首頁論壇板塊、登陸)數據訪問模塊,由網站來做這個判斷並調用不同的子模塊並不合適,可以加一個業務邏輯層來統一接受網站各種操作請求,這其實就是Facade。
何時采用
l 從代碼角度來說,如果你的程序有多個類是和一組其它接口發生關聯的話可以考慮在其中加一個門面類型。
l 從應用角度來說,如果子系統的接口是非常細的,調用方也有大量的邏輯來和這些接口發生關系,那麼就可以考慮使用Facade把客戶端與子系統的直接耦合關系進行化解。你可能會說,子系統改了門面不是照樣改?的確是需要改,但是如果客戶端本身的工作已經比較復雜,或者說可能有多個需要調用門面的地方,這個時候門面的好處就體現了。
實現要點
l 通過一個高層接口讓子系統和客戶端不發生直接關聯,使客戶端不受子系統變化的影響。
l Facade不僅僅針對代碼級別,在構架上,特別是WEB應用程序的構架上,Facade的應用非常普遍。
注意事項
l Facade不一定只能是一個,可以考慮把門面進行細分。