Java行為型設(shè)計模式之外觀設(shè)計模式詳解
編程是一門藝術(shù),大批量的改動顯然是非常丑陋的做法,用心的琢磨寫的代碼讓它變的更美觀。
在現(xiàn)實(shí)生活中,常常存在辦事較復(fù)雜的例子,如辦房產(chǎn)證或注冊一家公司,有時要同多個部門聯(lián)系,這時要是有一個綜合部門能解決一切手續(xù)問題就好了。
軟件設(shè)計也是這樣,當(dāng)一個系統(tǒng)的功能越來越強(qiáng),子系統(tǒng)會越來越多,客戶對系統(tǒng)的訪問也變得越來越復(fù)雜。這時如果系統(tǒng)內(nèi)部發(fā)生改變,客戶端也要跟著改變,這違背了“開閉原則”,也違背了“迪米特法則”,所以有必要為多個子系統(tǒng)提供一個統(tǒng)一的接口,從而降低系統(tǒng)的耦合度,這就是外觀模式的目標(biāo)。
1.外觀設(shè)計模式定義
外觀(Facade)模式又叫作門面模式,是一種通過為多個復(fù)雜的子系統(tǒng)提供一個一致的接口,而使這些子系統(tǒng)更加容易被訪問的模式。該模式對外有一個統(tǒng)一接口,外部應(yīng)用程序不用關(guān)心內(nèi)部子系統(tǒng)的具體細(xì)節(jié),這樣會大大降低應(yīng)用程序的復(fù)雜度,提高了程序的可維護(hù)性。
在日常編碼工作中,我們都在有意無意的大量使用外觀模式。只要是高層模塊需要調(diào)度多個子系統(tǒng)(2個以上的類對象),我們都會自覺地創(chuàng)建一個新的類封裝這些子系統(tǒng),提供精簡的接口,讓高層模塊可以更加容易地間接調(diào)用這些子系統(tǒng)的功能。尤其是現(xiàn)階段各種第三方SDK、開源類庫,很大概率都會使用外觀模式。
2.外觀設(shè)計模式優(yōu)點(diǎn)與不足
外觀(Facade)模式是“迪米特法則”的典型應(yīng)用,它有以下主要優(yōu)點(diǎn):
- 降低了子系統(tǒng)與客戶端之間的耦合度,使得子系統(tǒng)的變化不會影響調(diào)用它的客戶類。
- 對客戶屏蔽了子系統(tǒng)組件,減少了客戶處理的對象數(shù)目,并使得子系統(tǒng)使用起來更加容易。
- 降低了大型軟件系統(tǒng)中的編譯依賴性,簡化了系統(tǒng)在不同平臺之間的移植過程,因?yàn)榫幾g一個子系統(tǒng)不會影響其他的子系統(tǒng),也不會影響外觀對象。
外觀(Facade)模式的不足:
- 不能很好地限制客戶使用子系統(tǒng)類,很容易帶來未知風(fēng)險。
- 增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”。
3.外觀設(shè)計模式的實(shí)現(xiàn)思路
外觀(Facade)模式的結(jié)構(gòu)比較簡單,主要是定義了一個高層接口。它包含了對各個子系統(tǒng)的引用,客戶端可以通過它訪問各個子系統(tǒng)的功能。
外觀(Facade)模式包含以下主要角色:
- 外觀(Facade)角色:為多個子系統(tǒng)對外提供一個共同的接口。
- 子系統(tǒng)(Sub System)角色:實(shí)現(xiàn)系統(tǒng)的部分功能,客戶可以通過外觀角色訪問它。
- 客戶(Client)角色:通過一個外觀角色訪問各個子系統(tǒng)的功能。
4.外觀設(shè)計模式代碼示例
場景介紹:有加包裝服務(wù)、采摘服務(wù)、發(fā)貨服務(wù),為了方便客戶端使用,采用外觀設(shè)計模式進(jìn)行設(shè)計。
public class PackService {
/**
* 水果打包:防偽/加固/加急等
*/
public void doPack(){
AbstractFactory factory = new AppleFactory();
/*得到包裝*/
Bag bag = factory.getBag();
/*現(xiàn)需要增加防偽標(biāo)識*/
/*防偽功能*/
bag = new CheckedBagDecorator(bag);
/*加固功能*/
bag = new ReinforceBagDecorator(bag);
/*加急功能*/
bag = new SpeedDecorator(bag);
bag.pack();
}
public void doSomeThine(){
System.out.println("doSomeThine");
}
}
public class PickService {
/**
* 采摘水果
*/
public void doPick(){
//袋子型號
BagAbstraction pickBag = new SmallBag();
//袋子材質(zhì)
Material material = new Paper();
pickBag.setMaterial(material);
//開始采摘
pickBag.pick();
}
public void doSomeThine(){
System.out.println("doSomeThine");
}
}
public class SendService {
/**
* 指定目的地,發(fā)送快遞
*/
public void doSend(){
//根目錄
DistrictNode root = new DistrictNode("china");
//一線目錄
root.addChild(new DistrictNode("shang hai"));
root.addChild(new DistrictNode("tian jin"));
DistrictNode districtNode = new DistrictNode("bei jing");
root.addChild(districtNode);
//二級目錄
districtNode.addChild(new DistrictNode("hai dian qu"));
districtNode.addChild(new DistrictNode("xi cheng qu"));
DistrictNode districtNode2 = new DistrictNode("chao yang qu");
districtNode.addChild(districtNode2);
//三級目錄
districtNode2.addChild(new LeafNode("san li tun "));
districtNode2.addChild(new LeafNode("guo mao"));
System.out.println("請選定目的地:"+ JsonOutput.toJson(root));
/*以下物流運(yùn)輸業(yè)務(wù)*/
System.out.println("本次快遞目的地:beijing-chanyangqu-sanlitun");
}
public void doSomeThine(){
System.out.println("doSomeThine");
}
}
//外觀類
public class OrderFacade {
private PickService pickService;
private PackService packService;
private SendService sendService;
public OrderFacade(){
pickService = new PickService();
packService = new PackService();
sendService = new SendService();
}
/**
* 客戶訂單處理類
*/
public void doOrder(){
/*采摘*/
System.out.println("--------------");
pickService.doPick();
/*包裝*/
System.out.println("--------------");
packService.doPack();
/*快遞*/
System.out.println("--------------");
sendService.doSend();
}
}
public static void main(String[] args){
OrderFacade orderFacade = new OrderFacade();
orderFacade.doOrder();
}5.外觀模式的應(yīng)用場景
通常在以下情況下可以考慮使用外觀模式:
- 對分層結(jié)構(gòu)系統(tǒng)構(gòu)建時,使用外觀模式定義子系統(tǒng)中每層的入口點(diǎn)可以簡化子系統(tǒng)之間的依賴關(guān)系。
- 當(dāng)一個復(fù)雜系統(tǒng)的子系統(tǒng)很多時,外觀模式可以為系統(tǒng)設(shè)計一個簡單的接口供外界訪問。
- 當(dāng)客戶端與多個子系統(tǒng)之間存在很大的聯(lián)系時,引入外觀模式可將它們分離,從而提高子系統(tǒng)的獨(dú)立性和可移植性。
到此這篇關(guān)于Java行為型設(shè)計模式之外觀設(shè)計模式詳解的文章就介紹到這了,更多相關(guān)Java外觀模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring創(chuàng)建Bean完成后執(zhí)行指定代碼的幾種實(shí)現(xiàn)方式
在實(shí)際開發(fā)中經(jīng)常會遇到在spring容器加載完某個bean之后,需要執(zhí)行一些業(yè)務(wù)代碼的場景,本文給大家介紹Spring創(chuàng)建Bean完成后執(zhí)行指定代碼的幾種實(shí)現(xiàn)方式,感興趣的朋友一起看看吧2024-01-01
java線程池不同場景下使用示例經(jīng)驗(yàn)總結(jié)
這篇文章主要為大家介紹了java線程池不同場景如何使用的示例源碼及經(jīng)驗(yàn)總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
Java多線程并發(fā)開發(fā)之DelayQueue使用示例
這篇文章主要為大家詳細(xì)介紹了Java多線程并發(fā)開發(fā)之DelayQueue使用示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
詳解SpringBoot 發(fā)布ApplicationEventPublisher和監(jiān)聽ApplicationEvent事
這篇文章主要介紹了詳解SpringBoot 發(fā)布ApplicationEventPublisher和監(jiān)聽ApplicationEvent事件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-06-06
SpringBoot對Filter過濾器中的異常進(jìn)行全局處理方案詳解
這篇文章主要介紹了SpringBoot對Filter過濾器中的異常進(jìn)行全局處理,在SpringBoot中我們通過 @ControllerAdvice 注解和 @ExceptionHandler注解注冊了全局異常處理器,需要的朋友可以參考下2023-09-09
SpringBoot實(shí)現(xiàn)監(jiān)控Actuator,關(guān)閉redis監(jiān)測
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)監(jiān)控Actuator,關(guān)閉redis監(jiān)測,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11

