自己在家開網(wǎng)站做推廣百度優(yōu)化關(guān)鍵詞
目錄導(dǎo)航
- 什么是外觀模式
- 現(xiàn)實(shí)生活類比
- 實(shí)戰(zhàn)示例
- 門面模式的好處
- 門面模式源碼舉例
什么是外觀模式
外觀模式的英文名是Facade,意思是the front of a building,即建筑物的正面(門面),我個(gè)人更喜歡翻譯成門面模式。門面模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,所謂結(jié)構(gòu)型是指在代碼結(jié)構(gòu)設(shè)計(jì)方面的設(shè)計(jì)模式。
門面模式是一個(gè)類或一個(gè)模塊統(tǒng)一的功能入口,屏蔽掉系統(tǒng)內(nèi)部的實(shí)現(xiàn)及運(yùn)作方式,客戶端通過門面與系統(tǒng)交互,大大降低使用的復(fù)雜度,減少與系統(tǒng)的耦合。
現(xiàn)實(shí)生活類比
在一家餐館中,顧客可能需要各種服務(wù)。如:點(diǎn)餐、買單、詢問衛(wèi)生間、需要衛(wèi)生紙、臨時(shí)添加碗筷等等。如果每種服務(wù)都要到餐館不同的服務(wù)點(diǎn)找不同的人解決,顧客會(huì)瘋掉。而前臺(tái)就是整個(gè)餐館的門面,是餐館所有功能的輸出口,顧客通過前臺(tái)與餐館溝通,享受各種服務(wù),而不用關(guān)心前臺(tái)將會(huì)對(duì)此事如何安排(具體指派何人,以何種方式滿足顧客要求等)。
實(shí)戰(zhàn)示例
假如,我們要開發(fā)上述的餐館功能。
初始階段,業(yè)務(wù)相對(duì)簡(jiǎn)單,我們只有點(diǎn)餐與買單的功能。新建一個(gè)OrderManager類,
public class OrderManager {//點(diǎn)餐public void order(int tableNo) {System.out.println("table " + tableNo + " has ordered");}//買單public void bill(int tableNo, double dollars) {System.out.println("table " + tableNo + " bill:" + dollars);}
}
調(diào)用方使用該功能,
public static void main(String[] args) {//創(chuàng)建訂單管理模塊OrderManager orderManager = new OrderManager();//下單orderManager.order("001");//結(jié)賬orderManager.bill("001", 350.00);}
隨著業(yè)務(wù)迭代,我們又提供了一些詢問服務(wù),置于QueryService中,
public class QueryService {//衛(wèi)生間在哪里public String whereToilet(){return "it's xxxxx";}//...
}
隨著業(yè)務(wù)的復(fù)雜,我們不斷加入新的功能置于新的模塊。對(duì)于餐館功能的使用方來說,需要記住每個(gè)功能模塊對(duì)應(yīng)的類,使用復(fù)雜度不斷攀升。
public static void main(String[] args) {//創(chuàng)建訂單管理模塊OrderManager orderManager = new OrderManager();//下單orderManager.order("001");//結(jié)賬orderManager.bill("001", 350.00);//創(chuàng)建服務(wù)問詢模塊QueryService queryService = new QueryService();//詢問廁所queryService.whereToilet();//...}
我們使用門面模式可以解決上述問題。首先,我們創(chuàng)建一個(gè)門面類——RestaurantFacade,
此類作為整個(gè)餐館功能入口。
public class RestaurantFacade {private OrderManager orderManager = new OrderManager();private QueryService queryService = new QueryService();//...public OrderManager orderService() {return orderManager;}public QueryService queryService() {return queryService;}//...
}
對(duì)于調(diào)用方來說,所有的功能我都通過RestaurantFacade一個(gè)類獲取,不關(guān)心也沒必要知道其內(nèi)部的實(shí)現(xiàn)和運(yùn)作方式。
不管該系統(tǒng)后續(xù)添加新功能還是刪除了舊功能,交互門面不變。
public static void main(String[] args) {//創(chuàng)建門面類RestaurantFacade facade = new RestaurantFacade();//下單facade.orderService().order("001");//結(jié)賬facade.orderService().bill("001", 350.00);//詢問廁所facade.queryService().whereToilet();//...}
在這里,為了進(jìn)一步方便管理,我們RestaurantFacade對(duì)外提供的功能是返回子模塊,然后子模塊再調(diào)用具體功能。這種通常是在業(yè)務(wù)十分龐大復(fù)雜的情況下采取的策略。你也可以直接對(duì)外提供具體的功能,而把模塊信息封裝在門面類內(nèi)部。
以點(diǎn)餐為例:
public class RestaurantFacade {private OrderManager orderManager = new OrderManager();//...public void order(String tableNo) {orderManager.order(tableNo);}//...
}
調(diào)用方代碼:
public static void main(String[] args) {//創(chuàng)建門面類RestaurantFacade facade = new RestaurantFacade();//下單facade.order("001");//...}
門面模式的好處
外觀模式是一種設(shè)計(jì)模式,旨在簡(jiǎn)化復(fù)雜系統(tǒng)的接口,提供一個(gè)更簡(jiǎn)單的接口來訪問系統(tǒng)的子系統(tǒng)集合。它通過將系統(tǒng)的復(fù)雜性隱藏在一個(gè)單一的接口背后,使得客戶端代碼更容易使用。以下是外觀模式的幾個(gè)好處:
-
簡(jiǎn)化接口: 外觀模式提供了一個(gè)簡(jiǎn)化的接口,使得客戶端不需要了解系統(tǒng)的復(fù)雜性和內(nèi)部工作原理,只需與外觀對(duì)象進(jìn)行交互即可。
-
降低耦合性: 外觀模式有助于降低系統(tǒng)中各個(gè)子系統(tǒng)之間的耦合度,因?yàn)榭蛻舳酥恍枧c外觀對(duì)象交互,而不需要直接與子系統(tǒng)交互,從而減少了對(duì)子系統(tǒng)的依賴性。
-
隱藏實(shí)現(xiàn)細(xì)節(jié): 外觀模式將系統(tǒng)的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)隱藏在外部,使得系統(tǒng)更易于維護(hù)和修改。如果系統(tǒng)的內(nèi)部實(shí)現(xiàn)發(fā)生變化,只需更新外觀類而不影響客戶端代碼。
-
提高易用性: 外觀模式使得客戶端代碼更易于理解和使用,因?yàn)樗峁┝艘粋€(gè)簡(jiǎn)單的接口來訪問復(fù)雜系統(tǒng)的功能,而無需了解系統(tǒng)的內(nèi)部復(fù)雜性。
-
促進(jìn)代碼組織和管理: 外觀模式可以幫助將系統(tǒng)分解為更小的模塊,并將這些模塊組織成更易于管理和維護(hù)的結(jié)構(gòu)。
總的來說,外觀模式通過簡(jiǎn)化接口、降低耦合性、隱藏實(shí)現(xiàn)細(xì)節(jié)、提高易用性以及促進(jìn)代碼組織和管理等方面,可以幫助提高系統(tǒng)的可維護(hù)性、可擴(kuò)展性和可重用性。
門面模式源碼舉例
門面模式在第三方類庫中非常常見。例如Okhttp,我們使用它的功能,基本都是通過OkHttpClient這個(gè)類。
//創(chuàng)建門面對(duì)象,并進(jìn)行配置OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS)//鏈接超時(shí)為2秒,單位為秒.writeTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS)//讀取超時(shí).build();//執(zhí)行一個(gè)請(qǐng)求 okHttpClient.newCall(new Request.Builder().url("xxxx").build()).execute();