共同主題:施加策略#
本章討論的兩個模式有一個共同目的:對一群物件施加某種策略(imposing policy)。
- Facade 從上方施加策略——可見且具約束性
- Mediator 從下方施加策略——隱藏且賦能
Facade 模式#
意圖#
Facade 模式用於為一組擁有複雜通用介面的物件提供簡單且特定的介面。
範例:DB Facade#
以 DB 類別為例,它為 System.Data 命名空間中的 SqlConnection、SqlCommand、IDataReader 等複雜介面提供了一個專門針對 ProductData 的簡單介面:

Figure 23.2: QuickEntryMediator
DB 類別保護了 Application,使其不需要知道 System.Data 的內部細節。所有複雜性——如何初始化和關閉資料庫連線、如何將 ProductData 的成員對應到資料庫欄位、如何建立查詢和命令——都隱藏在 Facade 背後。
關鍵特徵#
- 約定式策略(Convention-based Policy):使用 Facade 意味著開發者已約定所有資料庫呼叫都必須經過
DB。如果Application的任何程式碼直接存取System.Data,就違反了約定 - 唯一經紀人(Sole Broker):
DB成為System.Data功能的唯一中介者 - Facade 可以用來隱藏程式的任何層面,但用來隱藏資料庫的做法已經非常普遍,這個模式也被稱為 Table Data Gateway
補充: 從
Application的角度來看,System.Data根本不存在;它被隱藏在 Facade 後面。
Mediator 模式#
意圖#
Mediator 模式也施加策略,但方式完全不同——Mediator 以隱藏且不具約束性的方式施加策略。
範例:QuickEntryMediator#
QuickEntryMediator 類別在幕後悄悄地綁定一個文字輸入欄位(TextBox)和一個清單(ListBox)。當使用者在文字欄位中輸入時,清單中第一個匹配的項目會自動被選取,讓使用者可以透過輸入縮寫快速選擇清單項目:
public class QuickEntryMediator
{
private TextBox itsTextBox;
private ListBox itsList;
public QuickEntryMediator(TextBox t, ListBox l)
{
itsTextBox = t;
itsList = l;
itsTextBox.TextChanged += new EventHandler(TextFieldChanged);
}
private void TextFieldChanged(object source, EventArgs args)
{
string prefix = itsTextBox.Text;
if (prefix.Length == 0)
{
itsList.ClearSelected();
return;
}
// 尋找匹配前綴的項目並選取
foreach (var item in itsList.Items)
{
if (item.ToString().StartsWith(prefix))
{
itsList.SetSelected(i, true);
return;
}
}
itsList.ClearSelected();
}
}關鍵特徵#
- 隱形存在:
ListBox和TextBox的使用者完全不知道 Mediator 的存在。它悄悄地坐在那裡,在沒有這些物件的許可或知識的情況下施加策略 - 只需建立即可:使用者只需建立
QuickEntryMediator的實例,不需要呼叫任何方法。建立後它就自行運作
Facade vs. Mediator 比較#
| 面向 | Facade | Mediator |
|---|---|---|
| 策略方向 | 從上方施加(from above) | 從下方施加(from below) |
| 可見性 | 可見且具約束性 | 隱藏且賦能 |
| 約定性質 | 基於約定(convention) | 既成事實(fait accompli) |
| 使用者認知 | 所有人同意使用 Facade 而非底層物件 | 使用者不知道 Mediator 的存在 |
結論#
- 需要大而可見的策略時,使用 Facade 從上方施加
- 需要細膩與隱蔽的策略時,使用 Mediator 從下方施加
- Facade 通常是約定的焦點——所有人同意使用 Facade 而非底層物件
- Mediator 則隱藏在使用者之外,其策略是既成事實而非約定