共同主題:施加策略#

本章討論的兩個模式有一個共同目的:對一群物件施加某種策略(imposing policy)。

  • Facade上方施加策略——可見且具約束性
  • Mediator下方施加策略——隱藏且賦能

Facade 模式#

意圖#

Facade 模式用於為一組擁有複雜通用介面的物件提供簡單且特定的介面

範例:DB Facade#

DB 類別為例,它為 System.Data 命名空間中的 SqlConnectionSqlCommandIDataReader 等複雜介面提供了一個專門針對 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();
  }
}

關鍵特徵#

  • 隱形存在ListBoxTextBox 的使用者完全不知道 Mediator 的存在。它悄悄地坐在那裡,在沒有這些物件的許可或知識的情況下施加策略
  • 只需建立即可:使用者只需建立 QuickEntryMediator 的實例,不需要呼叫任何方法。建立後它就自行運作

Facade vs. Mediator 比較#

面向FacadeMediator
策略方向從上方施加(from above)從下方施加(from below)
可見性可見且具約束性隱藏且賦能
約定性質基於約定(convention)既成事實(fait accompli)
使用者認知所有人同意使用 Facade 而非底層物件使用者不知道 Mediator 的存在

結論#

  • 需要大而可見的策略時,使用 Facade 從上方施加
  • 需要細膩與隱蔽的策略時,使用 Mediator 從下方施加
  • Facade 通常是約定的焦點——所有人同意使用 Facade 而非底層物件
  • Mediator 則隱藏在使用者之外,其策略是既成事實而非約定