10.外观模式(Facade Pattern)
動(dòng)機(jī)(Motivate):
????在軟件開(kāi)發(fā)系統(tǒng)中,客戶(hù)程序經(jīng)常會(huì)與復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)之間產(chǎn)生耦合,而導(dǎo)致客戶(hù)程序隨著子系統(tǒng)的變化而變化。那么如何簡(jiǎn)化客戶(hù)程序與子系統(tǒng)之間的交互接口?如何將復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)與客戶(hù)程序之間的依賴(lài)解耦?
意圖(Intent):
????為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,Facade模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
??? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? --------《設(shè)計(jì)模式》GOF
結(jié)構(gòu)圖(Struct):
?
?
適用性:
??? 1.為一個(gè)復(fù)雜子系統(tǒng)提供一個(gè)簡(jiǎn)單接口。
??? 2.提高子系統(tǒng)的獨(dú)立性。
??? 3.在層次化結(jié)構(gòu)中,可以使用Facade模式定義系統(tǒng)中每一層的入口。
生活中的例子:
代碼實(shí)現(xiàn):
????我們平時(shí)的開(kāi)發(fā)中其實(shí)已經(jīng)不知不覺(jué)的在用Fa?ade模式,現(xiàn)在來(lái)考慮這樣一個(gè)抵押系統(tǒng),當(dāng)有一個(gè)客戶(hù)來(lái)時(shí),有如下幾件事情需要確認(rèn):到銀行子系統(tǒng)查詢(xún)他是否有足夠多的存款,到信用子系統(tǒng)查詢(xún)他是否有良好的信用,到貸款子系統(tǒng)查詢(xún)他有無(wú)貸款劣跡。只有這三個(gè)子系統(tǒng)都通過(guò)時(shí)才可進(jìn)行抵押。我們先不考慮Fa?ade模式,那么客戶(hù)程序就要直接訪問(wèn)這些子系統(tǒng),分別進(jìn)行判斷。類(lèi)結(jié)構(gòu)圖下:?
在這個(gè)程序中,我們首先要有一個(gè)顧客類(lèi),它是一個(gè)純數(shù)據(jù)類(lèi),并無(wú)任何操作,示意代碼:
?
//顧客類(lèi)
public class Customer{private string _name;public Customer(string name){this._name = name;}public string Name{get { return _name; }}}?
下面這三個(gè)類(lèi)均是子系統(tǒng)類(lèi),示意代碼:
?
//信用子系統(tǒng)public class Credit{public bool HasGoodCredit(Customer c){Console.WriteLine("Check credit for " + c.Name);return true;}}
?
//貸款子系統(tǒng)public class Loan{public bool HasNoBadLoans(Customer c){Console.WriteLine("Check loans for " + c.Name);return true;}} }
?
看客戶(hù)程序的調(diào)用:
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模式的情況下,客戶(hù)程序與三個(gè)子系統(tǒng)都發(fā)生了耦合,這種耦合使得客戶(hù)程序依賴(lài)于子系統(tǒng),當(dāng)子系統(tǒng)化時(shí),客戶(hù)程序也將面臨很多變化的挑戰(zhàn)。一個(gè)合情合理的設(shè)計(jì)就是為這些子系統(tǒng)創(chuàng)建一個(gè)統(tǒng)一的接口,這個(gè)接口簡(jiǎn)化了客戶(hù)程序的判斷操作??匆幌乱隖a?ade模式后的類(lèi)結(jié)構(gòu)圖:
?
?
顧客類(lèi)和子系統(tǒng)類(lèi)的實(shí)現(xiàn)仍然如下:
//銀行子系統(tǒng)public class Bank{public bool HasSufficientSavings(Customer c, int amount){Console.WriteLine("Check bank for " + c.Name);return true;}}//信用子系統(tǒng)public class Credit{public bool HasGoodCredit(Customer c){Console.WriteLine("Check credit for " + c.Name);return true;}}//貸款子系統(tǒng)public class Loan{public bool HasNoBadLoans(Customer c){Console.WriteLine("Check loans for " + c.Name);return true;}}?
//顧客類(lèi)public class Customer{private string _name;public Customer(string name){this._name = name;}public string Name{get { return _name; }}}
?
外觀類(lèi)Mortage的實(shí)現(xiàn)如下:
?
而此時(shí)客戶(hù)程序的實(shí)現(xiàn):
//客戶(hù)程序類(lèi)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模式后,客戶(hù)程序只與Mortgage發(fā)生依賴(lài),也就是Mortgage屏蔽了子系統(tǒng)之間的復(fù)雜的操作,達(dá)到了解耦內(nèi)部子系統(tǒng)與客戶(hù)程序之間的依賴(lài)。
.NET架構(gòu)中的Facade模式
Facade模式在實(shí)際開(kāi)發(fā)中最多的運(yùn)用當(dāng)屬開(kāi)發(fā)N層架的應(yīng)用程序了,一個(gè)典型的N層結(jié)構(gòu)如下:
?
在這個(gè)架構(gòu)中,總共分為四個(gè)邏輯層,分別為:用戶(hù)層UI,業(yè)務(wù)外觀層Business Facade,業(yè)務(wù)規(guī)則層Business Rule,數(shù)據(jù)訪問(wèn)層Data Access。其中Business Facade層的職責(zé)如下:
l?????????從“用戶(hù)”層接收用戶(hù)輸入
l?????????如果請(qǐng)求需要對(duì)數(shù)據(jù)進(jìn)行只讀訪問(wèn),則可能使用“數(shù)據(jù)訪問(wèn)”層
l?????????將請(qǐng)求傳遞到“業(yè)務(wù)規(guī)則”層
l?????????將響應(yīng)從“業(yè)務(wù)規(guī)則”層返回到“用戶(hù)”層
l?????????在對(duì)“業(yè)務(wù)規(guī)則”層的調(diào)用之間維護(hù)臨時(shí)狀態(tài)
對(duì)這一架構(gòu)最好的體現(xiàn)就是Duwamish示 例了。在該應(yīng)用程序中,有部分操作只是簡(jiǎn)單的從數(shù)據(jù)庫(kù)根據(jù)條件提取數(shù)據(jù),不需要經(jīng)過(guò)任何處理,而直接將數(shù)據(jù)顯示到網(wǎng)頁(yè)上,比如查詢(xún)某類(lèi)別的圖書(shū)列表。而另 外一些操作,比如計(jì)算定單中圖書(shū)的總價(jià)并根據(jù)顧客的級(jí)別計(jì)算回扣等等,這部分往往有許多不同的功能的類(lèi),操作起來(lái)也比較復(fù)雜。如果采用傳統(tǒng)的三層結(jié)構(gòu),這 些商業(yè)邏輯一般是會(huì)放在中間層,那么對(duì)內(nèi)部的這些大量種類(lèi)繁多,使用方法也各異的不同的類(lèi)的調(diào)用任務(wù),就完全落到了表示層。這樣勢(shì)必會(huì)增加表示層的代碼 量,將表示層的任務(wù)復(fù)雜化,和表示層只負(fù)責(zé)接受用戶(hù)的輸入并返回結(jié)果的任務(wù)不太相稱(chēng),并增加了層與層之間的耦合程度。于是就引入了一個(gè)Facade層,讓這個(gè)Facade來(lái)負(fù)責(zé)管理系統(tǒng)內(nèi)部類(lèi)的調(diào)用,并為表示層提供了一個(gè)單一而簡(jiǎn)單的接口。看一下Duwamish結(jié)構(gòu)圖:
?
從圖中可以看到,UI層將請(qǐng)求發(fā)送給業(yè)務(wù)外觀層,業(yè)務(wù)外觀層對(duì)請(qǐng)求進(jìn)行初步的處理,判斷是否需要調(diào)用業(yè)務(wù)規(guī)則層,還是直接調(diào)用數(shù)據(jù)訪問(wèn)層獲取數(shù)據(jù)。最后由數(shù)據(jù)訪問(wèn)層訪問(wèn)數(shù)據(jù)庫(kù)并按照來(lái)時(shí)的步驟返回結(jié)果到UI層,來(lái)看具體的代碼實(shí)現(xiàn)。
在獲取商品目錄的時(shí)候,Web UI調(diào)用業(yè)務(wù)外觀層:
productSystem = new ProductSystem();categorySet = productSystem.GetCategories(categoryID);?
業(yè)務(wù)外觀層直接調(diào)用了數(shù)據(jù)訪問(wèn)層:
?
在添加訂單時(shí),UI調(diào)用業(yè)務(wù)外觀層:
?
業(yè)務(wù)外觀層調(diào)用業(yè)務(wù)規(guī)則層:
?
?
業(yè)務(wù)規(guī)則層進(jìn)行復(fù)雜的邏輯處理后,再調(diào)用數(shù)據(jù)訪問(wèn)層:
public OrderData AddOrder(OrderData order){//// Check preconditions// ApplicationAssert.CheckCondition(order != null, "Order is required", ApplicationAssert.LineNumber);(new BusinessRules.Order()).InsertOrder(order);return order;}?
業(yè)務(wù)規(guī)則層進(jìn)行復(fù)雜的邏輯處理后,再調(diào)用數(shù)據(jù)訪問(wèn)層: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模式的個(gè)要點(diǎn):
??? 從客戶(hù)程序的角度來(lái)看,Facade模式不僅簡(jiǎn)化了整個(gè)組件系統(tǒng)的接口,同時(shí)對(duì)于組件內(nèi)部與外部客戶(hù)程序來(lái)說(shuō),從某種程度上也達(dá)到了一種“解耦”的效果----內(nèi)部子系統(tǒng)的任何變化不會(huì)影響到Facade接口的變化。
??? Facade設(shè)計(jì)模式更注重從架構(gòu)的層次去看整個(gè)系統(tǒng),而不是單個(gè)類(lèi)的層次。Facdae很多時(shí)候更是一種架構(gòu)
設(shè)計(jì)模式。
??? 注意區(qū)分Facade模式、Adapter模式、Bridge模式與Decorator模式。Facade模式注重簡(jiǎn)化接口,Adapter模式注重轉(zhuǎn)換接口,Bridge模式注重分離接口(抽象)與其實(shí)現(xiàn),Decorator模式注重穩(wěn)定接口的前提下為對(duì)象擴(kuò)展功能。
轉(zhuǎn)載于:https://www.cnblogs.com/1285026182YUAN/p/5162752.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的10.外观模式(Facade Pattern)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 解决IE只能用管理员身份运行才能正常
- 下一篇: jdk的一条命令查看运行参数