1. 程式人生 > >23種設計模式-9.外觀模式(Facade Pattern)

23種設計模式-9.外觀模式(Facade Pattern)

動機(Motivate):
    在軟體開發系統中,客戶程式經常會與複雜系統的內部子系統之間產生耦合,而導致客戶程式隨著子系統的變化而變化。那麼如何簡化客戶程式與子系統之間的互動介面?如何將複雜系統的內部子系統與客戶程式之間的依賴解耦?
意圖(Intent):
    為子系統中的一組介面提供一個一致的介面,Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
                                                                         --------《設計模式》GOF
結構圖(Struct):
                
                
            
適用性:

    1.為一個複雜子系統提供一個簡單介面。

    2.提高子系統的獨立性。

    3.在層次化結構中,可以使用Facade模式定義系統中每一層的入口。
生活中的例子:
                
程式碼實現:
    我們平時的開發中其實已經不知不覺的在用Façade模式,現在來考慮這樣一個抵押系統,當有一個客戶來時,有如下幾件事情需要確認:到銀行子系統查詢他是否有足夠多的存款,到信用子系統查詢他是否有良好的信用,到貸款子系統查詢他有無貸款劣跡。只有這三個子系統都通過時才可進行抵押。我們先不考慮Façade模式,那麼客戶程式就要直接訪問這些子系統,分別進行判斷。類結構圖下: 
                 
    
在這個程式中,我們首先要有一個顧客類,它是一個純資料類,並無任何操作,示意程式碼:

 1 //顧客類 2 publicclass Customer 3 { 4 privatestring _name; 5  6 public Customer(string name) 7     { 8 this._name = name; 9     }10 11 publicstring Name12     {13 get { return _name; }14     }15 }


下面這三個類均是子系統類,示意程式碼:

 1 //銀行子系統 2 publicclass Bank 3 { 4 publicbool HasSufficientSavings(Customer c, int amount)

 5     { 6         Console.WriteLine("Check bank for " + c.Name); 7 returntrue; 8     } 9 }10 11 //信用子系統12 publicclass Credit13 {14 publicbool HasGoodCredit(Customer c)15     {16         Console.WriteLine("Check credit for " + c.Name);17 returntrue;18     }19 }20 21 //貸款子系統22 publicclass Loan23 {24 publicbool HasNoBadLoans(Customer c)25     {26         Console.WriteLine("Check loans for " + c.Name);27 returntrue;28     }29 }


看客戶程式的呼叫:

 1 //客戶程式 2 publicclass MainApp 3 { 4 privateconstint _amount = 12000; 5  6 publicstaticvoid Main() 7     { 8         Bank bank = new Bank(); 9         Loan loan = new Loan();10         Credit credit = new Credit();11 12         Customer customer = new Customer("Ann McKinsey");13 14 bool eligible = true;15 16 if (!bank.HasSufficientSavings(customer, _amount))17         {18             eligible = false;19         }20 elseif (!loan.HasNoBadLoans(customer))21         {22             eligible = false;23         }24 elseif (!credit.HasGoodCredit(customer))25         {26             eligible = false;27         }28 29         Console.WriteLine("\n" + customer.Name + " has been " + (eligible ? "Approved" : "Rejected"));30         Console.ReadLine();31     }32 }


可以看到,在不用Façade模式的情況下,客戶程式與三個子系統都發生了耦合,這種耦合使得客戶程式依賴於子系統,當子系統化時,客戶程式也將面臨很多變化的挑戰。一個合情合理的設計就是為這些子系統建立一個統一的介面,這個介面簡化了客戶程式的判斷操作。看一下引入Façade模式後的類結構圖:
           變

外觀類Mortage的實現如下:

 1 /外觀類 2 publicclass Mortgage 3 { 4 private Bank bank = new Bank(); 5 private Loan loan = new Loan(); 6 private Credit credit = new Credit(); 7  8 publicbool IsEligible(Customer cust, int amount) 9     {10         Console.WriteLine("{0} applies for {1:C} loan\n",11           cust.Name, amount);12 13 bool eligible = true;14 15 if (!bank.HasSufficientSavings(cust, amount))16         {17             eligible = false;18         }19 elseif (!loan.HasNoBadLoans(cust))20         {21             eligible = false;22         }23 elseif (!credit.HasGoodCredit(cust))24         {25             eligible = false;26         }27 28 return eligible;29     }30 }

顧客類和子系統類的實現仍然如下:

 1 //銀行子系統 2 publicclass Bank 3 { 4 publicbool HasSufficientSavings(Customer c, int amount) 5     { 6         Console.WriteLine("Check bank for " + c.Name); 7 returntrue; 8     } 9 }10 11 //信用證子系統12 publicclass Credit13 {14 publicbool HasGoodCredit(Customer c)15     {16         Console.WriteLine("Check credit for " + c.Name);17 returntrue;18     }19 }20 21 //貸款子系統22 publicclass Loan23 {24 publicbool HasNoBadLoans(Customer c)25     {26         Console.WriteLine("Check loans for " + c.Name);27 returntrue;28     }29 }30 31 //顧客類32 publicclass Customer33 {34 privatestring name;35 36 public Customer(string name)37     {38 this.name = name;39     }40 41 publicstring Name42     {43 get { return name; }44     }45 }

而此時客戶程式的實現:

 1 //客戶程式類 2 publicclass MainApp 3 { 4 publicstaticvoid Main() 5     { 6 //外觀 7         Mortgage mortgage = new Mortgage(); 8  9         Customer customer = new Customer("Ann McKinsey");10 bool eligable = mortgage.IsEligible(customer, 125000);11 12         Console.WriteLine("\n" + customer.Name +13             " has been " + (eligable ? "Approved" : "Rejected")); 14         Console.ReadLine();15     }16 }

可以看到引入Façade模式後,客戶程式只與Mortgage發生依賴,也就是Mortgage遮蔽了子系統之間的複雜的操作,達到了解耦內部子系統與客戶程式之間的依賴。