10.外观模式(Facade Pattern)
動機(Motivate):
????在軟件開發系統中,客戶程序經常會與復雜系統的內部子系統之間產生耦合,而導致客戶程序隨著子系統的變化而變化。那么如何簡化客戶程序與子系統之間的交互接口?如何將復雜系統的內部子系統與客戶程序之間的依賴解耦?
意圖(Intent):
????為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
??? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? --------《設計模式》GOF
結構圖(Struct):
?
?
適用性:
??? 1.為一個復雜子系統提供一個簡單接口。
??? 2.提高子系統的獨立性。
??? 3.在層次化結構中,可以使用Facade模式定義系統中每一層的入口。
生活中的例子:
代碼實現:
????我們平時的開發中其實已經不知不覺的在用Fa?ade模式,現在來考慮這樣一個抵押系統,當有一個客戶來時,有如下幾件事情需要確認:到銀行子系統查詢他是否有足夠多的存款,到信用子系統查詢他是否有良好的信用,到貸款子系統查詢他有無貸款劣跡。只有這三個子系統都通過時才可進行抵押。我們先不考慮Fa?ade模式,那么客戶程序就要直接訪問這些子系統,分別進行判斷。類結構圖下:?
在這個程序中,我們首先要有一個顧客類,它是一個純數據類,并無任何操作,示意代碼:
?
//顧客類
public class Customer{private string _name;public Customer(string name){this._name = name;}public string Name{get { return _name; }}}?
下面這三個類均是子系統類,示意代碼:
?
//信用子系統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;}} }
?
看客戶程序的調用:
class Program{private const int _amount = 12000;static void Main(string[] args){Bank bank = new Bank();Credit credit = new Credit();Loan loan = new Loan();Customer customer = new Customer("Ann McKinsey");bool eligible = true;if (!bank.HasSufficientSavings(customer, _amount)){eligible = false;}else if (!credit.HasGoodCredit(customer)){eligible = false;}else if (!loan.HasNoBadLoans(customer)){eligible = false;}Console.WriteLine("\n" + customer.Name + " has been " + (eligible ? "Approved" : "Rejected"));Console.ReadLine();}}
?
可以看到,在不用Fa?ade模式的情況下,客戶程序與三個子系統都發生了耦合,這種耦合使得客戶程序依賴于子系統,當子系統化時,客戶程序也將面臨很多變化的挑戰。一個合情合理的設計就是為這些子系統創建一個統一的接口,這個接口簡化了客戶程序的判斷操作。看一下引入Fa?ade模式后的類結構圖:
?
?
顧客類和子系統類的實現仍然如下:
//銀行子系統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; }}}
?
外觀類Mortage的實現如下:
?
而此時客戶程序的實現:
//客戶程序類class Program{private const int _amount = 12000;static void Main(string[] args){//外觀Mortgage mortgage = new Mortgage();Customer customer = new Customer("Ann McKinsey");bool eligable = mortgage.IsEligible(customer, _amount);Console.WriteLine("\n" + customer.Name + " has been " + (eligable ? "Approved" : "Rejected"));Console.ReadLine(); }}
?
可以看到引入Fa?ade模式后,客戶程序只與Mortgage發生依賴,也就是Mortgage屏蔽了子系統之間的復雜的操作,達到了解耦內部子系統與客戶程序之間的依賴。
.NET架構中的Facade模式
Facade模式在實際開發中最多的運用當屬開發N層架的應用程序了,一個典型的N層結構如下:
?
在這個架構中,總共分為四個邏輯層,分別為:用戶層UI,業務外觀層Business Facade,業務規則層Business Rule,數據訪問層Data Access。其中Business Facade層的職責如下:
l?????????從“用戶”層接收用戶輸入
l?????????如果請求需要對數據進行只讀訪問,則可能使用“數據訪問”層
l?????????將請求傳遞到“業務規則”層
l?????????將響應從“業務規則”層返回到“用戶”層
l?????????在對“業務規則”層的調用之間維護臨時狀態
對這一架構最好的體現就是Duwamish示 例了。在該應用程序中,有部分操作只是簡單的從數據庫根據條件提取數據,不需要經過任何處理,而直接將數據顯示到網頁上,比如查詢某類別的圖書列表。而另 外一些操作,比如計算定單中圖書的總價并根據顧客的級別計算回扣等等,這部分往往有許多不同的功能的類,操作起來也比較復雜。如果采用傳統的三層結構,這 些商業邏輯一般是會放在中間層,那么對內部的這些大量種類繁多,使用方法也各異的不同的類的調用任務,就完全落到了表示層。這樣勢必會增加表示層的代碼 量,將表示層的任務復雜化,和表示層只負責接受用戶的輸入并返回結果的任務不太相稱,并增加了層與層之間的耦合程度。于是就引入了一個Facade層,讓這個Facade來負責管理系統內部類的調用,并為表示層提供了一個單一而簡單的接口。看一下Duwamish結構圖:
?
從圖中可以看到,UI層將請求發送給業務外觀層,業務外觀層對請求進行初步的處理,判斷是否需要調用業務規則層,還是直接調用數據訪問層獲取數據。最后由數據訪問層訪問數據庫并按照來時的步驟返回結果到UI層,來看具體的代碼實現。
在獲取商品目錄的時候,Web UI調用業務外觀層:
productSystem = new ProductSystem();categorySet = productSystem.GetCategories(categoryID);?
業務外觀層直接調用了數據訪問層:
?
在添加訂單時,UI調用業務外觀層:
?
業務外觀層調用業務規則層:
?
?
業務規則層進行復雜的邏輯處理后,再調用數據訪問層:
public OrderData AddOrder(OrderData order){//// Check preconditions// ApplicationAssert.CheckCondition(order != null, "Order is required", ApplicationAssert.LineNumber);(new BusinessRules.Order()).InsertOrder(order);return order;}?
業務規則層進行復雜的邏輯處理后,再調用數據訪問層:public bool InsertOrder(OrderData order){//// Assume it's good// bool isValid = true;// // Validate order summary// DataRow summaryRow = order.Tables[OrderData.ORDER_SUMMARY_TABLE].Rows[0];summaryRow.ClearErrors();if (CalculateShipping(order) != (Decimal)(summaryRow[OrderData.SHIPPING_HANDLING_FIELD])){summaryRow.SetColumnError(OrderData.SHIPPING_HANDLING_FIELD, OrderData.INVALID_FIELD);isValid = false;}if (CalculateTax(order) != (Decimal)(summaryRow[OrderData.TAX_FIELD])){summaryRow.SetColumnError(OrderData.TAX_FIELD, OrderData.INVALID_FIELD);isValid = false;}// // Validate shipping info// isValid &= IsValidField(order, OrderData.SHIPPING_ADDRESS_TABLE, OrderData.SHIP_TO_NAME_FIELD, 40);//// Validate payment info // DataRow paymentRow = order.Tables[OrderData.PAYMENT_TABLE].Rows[0];paymentRow.ClearErrors();isValid &= IsValidField(paymentRow, OrderData.CREDIT_CARD_TYPE_FIELD, 40);isValid &= IsValidField(paymentRow, OrderData.CREDIT_CARD_NUMBER_FIELD, 32);isValid &= IsValidField(paymentRow, OrderData.EXPIRATION_DATE_FIELD, 30);isValid &= IsValidField(paymentRow, OrderData.NAME_ON_CARD_FIELD, 40);isValid &= IsValidField(paymentRow, OrderData.BILLING_ADDRESS_FIELD, 255);//// Validate the order items and recalculate the subtotal// DataRowCollection itemRows = order.Tables[OrderData.ORDER_ITEMS_TABLE].Rows;Decimal subTotal = 0;foreach (DataRow itemRow in itemRows){itemRow.ClearErrors();subTotal += (Decimal)(itemRow[OrderData.EXTENDED_FIELD]);if ((Decimal)(itemRow[OrderData.PRICE_FIELD]) <= 0){itemRow.SetColumnError(OrderData.PRICE_FIELD, OrderData.INVALID_FIELD);isValid = false;}if ((short)(itemRow[OrderData.QUANTITY_FIELD]) <= 0){itemRow.SetColumnError(OrderData.QUANTITY_FIELD, OrderData.INVALID_FIELD);isValid = false;}}//// Verify the subtotal// if (subTotal != (Decimal)(summaryRow[OrderData.SUB_TOTAL_FIELD])){summaryRow.SetColumnError(OrderData.SUB_TOTAL_FIELD, OrderData.INVALID_FIELD);isValid = false;}if (isValid){using (DataAccess.Orders ordersDataAccess = new DataAccess.Orders()){return (ordersDataAccess.InsertOrderDetail(order)) > 0;}}elsereturn false;}}
?
Facade模式的個要點:
??? 從客戶程序的角度來看,Facade模式不僅簡化了整個組件系統的接口,同時對于組件內部與外部客戶程序來說,從某種程度上也達到了一種“解耦”的效果----內部子系統的任何變化不會影響到Facade接口的變化。
??? Facade設計模式更注重從架構的層次去看整個系統,而不是單個類的層次。Facdae很多時候更是一種架構
設計模式。
??? 注意區分Facade模式、Adapter模式、Bridge模式與Decorator模式。Facade模式注重簡化接口,Adapter模式注重轉換接口,Bridge模式注重分離接口(抽象)與其實現,Decorator模式注重穩定接口的前提下為對象擴展功能。
轉載于:https://www.cnblogs.com/1285026182YUAN/p/5162752.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的10.外观模式(Facade Pattern)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决IE只能用管理员身份运行才能正常
- 下一篇: jdk的一条命令查看运行参数