外觀(Facade)模式
什麼是(Facade)模式?
Facade(外觀)模式為子系統中的各類(或結構與方法)提供一個簡明一致的介面,隱藏子系統的複雜性,使子系統更加容易使用(出自百度文庫)。即當子系統複雜或者繁鎖時,我們讓子系統提供一個視窗,程式中稱為介面,其它程式或者物件就通過這個視窗(介面)與此子系統聯絡。介面可以是類或方法等。這樣就簡化了子系統的使用。
作用是什麼?
簡化子系統的使用。
如何實現?
當子系統(或者物件)使用很複雜時,我們建立一個介面(視窗)物件,將子系統的複雜的使用方法寫在此象中,其它物件或程式通過呼叫此介面(視窗)來使用系統。即在其它物件或程式中加了一層,此層用於呼叫子系統。而其它物件使用些層來呼叫子系統,而不管此層如何呼叫子系統。
概述
在軟體開發系統中,客戶程式經常會與複雜系統的內部子系統之間產生耦合,而導致客戶程式隨著子系統的變化而變化。那麼如何簡化客戶程式與子系統之間的互動介面?如何將複雜系統的內部子系統與客戶程式之間的依賴解耦?這就是要說的Façade 模式。
意圖
為子系統中的一組介面提供一個一致的介面,Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。[GOF 《設計模式》]
示意圖
門面模式沒有一個一般化的類圖描述,下面是一個示意性的物件圖:
圖1 Façade模式示意性物件圖
生活中的例子
外觀模式為子系統中的介面定義了一個統一的更高層次的介面,以便於使用。當消費者按照目錄採購時,則體現了一個外觀模式。消費者撥打一個號碼與客服代表聯絡,客服代表則扮演了這個
圖2使用電話訂貨例子的外觀模式物件圖
Facade模式解說
我們平時的開發中其實已經不知不覺的在用Façade模式,現在來考慮這樣一個抵押系統,當有一個客戶來時,有如下幾件事情需要確認:到銀行子系統查詢他是否有足夠多的存款,到信用子系統查詢他是否有良好的信用,到貸款子系統查詢他有無貸款劣跡。只有這三個子系統都通過時才可進行抵押。我們先不考慮Façade模式,那麼客戶程式就要直接訪問這些子系統,分別進行判斷。類結構圖下:
圖3
在這個程式中,我們首先要有一個顧客類,它是一個純資料類,並無任何操作,示意程式碼:
//顧客類public class Customer
{
private string _name;
public Customer(string name)
{
this._name = name;
}
public string Name
{
get { return _name; }
}
}
下面這三個類均是子系統類,示意程式碼:
public class Bank
{
public bool HasSufficientSavings(Customer c, int amount)
{
Console.WriteLine("Check bank for " + c.Name);
return true;
}
}
//信用子系統
public class Credit
{
public bool HasGoodCredit(Customer c)
{
Console.WriteLine("Check credit for " + c.Name);
return true;
}
}
//貸款子系統
public class Loan
{
public bool HasNoBadLoans(Customer c)
{
Console.WriteLine("Check loans for " + c.Name);
return true;
}
}
來看客戶程式的呼叫:
//客戶程式public class MainApp
{
private const int _amount = 12000;
public static void Main()
{
Bank bank = new Bank();
Loan loan = new Loan();
Credit credit = new Credit();
Customer customer = new Customer("Ann McKinsey");
bool eligible = true;
if (!bank.HasSufficientSavings(customer, _amount))
{
eligible = false;
}
else if (!loan.HasNoBadLoans(customer))
{
eligible = false;
}
else if (!credit.HasGoodCredit(customer))
{
eligible = false;
}
Console.WriteLine("\n" + customer.Name + " has been " + (eligible ? "Approved" : "Rejected"));
Console.ReadLine();
}
}
可以看到,在不用Façade模式的情況下,客戶程式與三個子系統都發生了耦合,這種耦合使得客戶程式依賴於子系統,當子系統變化時,客戶程式也將面臨很多變化的挑戰。一個合情合理的設計就是為這些子系統建立一個統一的介面,這個介面簡化了客戶程式的判斷操作。看一下引入Façade模式後的類結構圖:
圖4
門面類Mortage的實現如下:
//外觀類public class Mortgage
{
private Bank bank = new Bank();
private Loan loan = new Loan();
private Credit credit = new Credit();
public bool IsEligible(Customer cust, int amount)
{
Console.WriteLine("{0} applies for {1:C} loan\n",
cust.Name, amount);
bool eligible = true;
if (!bank.HasSufficientSavings(cust, amount))
{
eligible = false;
}
else if (!loan.HasNoBadLoans(cust))
{
eligible = false;
}
else if (!credit.HasGoodCredit(cust))
{
eligible = false;
}
return eligible;
}
}
顧客類和子系統類的實現仍然如下:
public class Bank
{
public bool HasSufficientSavings(Customer c, int amount)
{
Console.WriteLine("Check bank for " + c.Name);
return true;
}
}
//信用證子系統
public class Credit
{
public bool HasGoodCredit(Customer c)
{
Console.WriteLine("Check credit for " + c.Name);
return true;
}
}
//貸款子系統
public class Loan
{
public bool HasNoBadLoans(Customer c)
{
Console.WriteLine("Check loans for " + c.Name);
return true;
}
}
//顧客類
public class Customer
{
private string name;
public Customer(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
而此時客戶程式的實現:
//客戶程式類public class MainApp
{
public static void Main()
{
//外觀
Mortgage mortgage = new Mortgage();
Customer customer = new Customer("Ann McKinsey");
bool eligable = mortgage.IsEligible(customer, 125000);
Console.WriteLine("\n" + customer.Name +
" has been " + (eligable ? "Approved" : "Rejected"));
Console.ReadLine();
}