《三國演義》中有曰:劉備、諸葛亮趁曹操赤壁之戰(zhàn)失利,大肆擴(kuò)充地盤,先后占領(lǐng)荊州大部地區(qū),引起東吳孫權(quán)的警惕。為了限制劉備勢(shì)力的發(fā)展,魯肅奉命向劉備討還荊州,但遭到拒絕。東吳大都督周瑜向?qū)O權(quán)獻(xiàn)計(jì):趁劉備的甘夫人病故,用孫權(quán)的妹妹孫仁為誘餌,將劉備“賺到南徐,妻子不能勾得,幽囚在獄中”。 但是,這個(gè)詭計(jì)被諸葛亮一眼識(shí)破。他將計(jì)就計(jì),讓劉備“擇日便去就親”,并派趙云前去保護(hù),并給了趙云三個(gè)錦囊,教趙云“依次而行”。結(jié)果,使東吳“賠了夫人又折兵”。此為諸葛亮的錦囊三妙計(jì)。
一、三妙計(jì)
妙計(jì)一:見喬國老,并把劉備娶親的事情搞得東吳人盡皆知。
妙計(jì)二:用謊言(曹操打荊州)騙泡在溫柔鄉(xiāng)里的劉備回去。
妙計(jì)三:讓孫夫人擺平東吳的追兵,她是孫權(quán)妹妹,東吳將領(lǐng)懼她三分。
二、妙計(jì)的兩種實(shí)施方案
1.把三個(gè)錦囊直接交給劉備,讓劉備根據(jù)情況打開錦囊。
2.把錦囊交給趙云,趙云按照諸葛亮的囑咐,依次按照情況使用錦囊。
三、劉備用妙計(jì)
①妙計(jì)的接口
public interface Strategy {
//妙計(jì)內(nèi)容
public void carryOut();
}
②妙計(jì)一
public class StrategyOne implements Strategy {
@Override
public void carryOut() {
System.out.println("見喬國老,并把劉備娶親的事情搞得東吳人盡皆知。");
}
}
③妙計(jì)二
public class StrategyTwo implements Strategy {
@Override
public void carryOut() {
System.out.println("用謊言(曹操打荊州)騙泡在溫柔鄉(xiāng)里的劉備回去。");
}
}
④妙計(jì)三
public class StrategyThree implements Strategy {
@Override
public void carryOut() {
System.out.println("讓孫夫人擺平東吳的追兵。");
}
}
⑤劉備使用妙計(jì)
public class Client {
public static void main(String[] args) {
//劉備一行人到達(dá)南徐的時(shí)候,打開第一個(gè)錦囊
Strategy strategyOne=new StrategyOne();
strategyOne.carryOut();
//周瑜和孫權(quán)通過計(jì)謀使劉備沉迷在溫柔鄉(xiāng)無法自拔
Strategy strategyTwo=new StrategyTwo();
strategyTwo.carryOut();
//周瑜看計(jì)謀不行,出兵攔殺劉備
Strategy strategyThree=new StrategyThree();
strategyThree.carryOut();
}
}
輸出的結(jié)果為:
//劉備一行人到達(dá)南徐的時(shí)候,打開第一個(gè)錦囊
見喬國老,并把劉備娶親的事情搞得東吳人盡皆知。
//周瑜和孫權(quán)通過計(jì)謀使劉備沉迷在溫柔鄉(xiāng)無法自拔
用謊言(曹操打荊州)騙泡在溫柔鄉(xiāng)里的劉備回去。
//周瑜看計(jì)謀不行,出兵攔殺劉備
讓孫夫人擺平東吳的追兵。
忽略其他正常因素(諸葛亮不可能把錦囊交給劉備實(shí)施),代碼角度分析這種方案帶來的問題
錦囊使用是有前提的,要根據(jù)每個(gè)階段來使用對(duì)應(yīng)的錦囊,在編寫代碼中要清楚它們的順序,一旦出錯(cuò)就會(huì)造成劉備死翹翹。這在面向?qū)ο蟮木幊讨惺菢O度地不適合,它根本就沒有完成一個(gè)類所具有的單一職責(zé)。
外界訪問直接深入到子系統(tǒng)內(nèi)部,相互之間是一種強(qiáng)耦合關(guān)系,這樣的強(qiáng)依賴是系統(tǒng)設(shè)計(jì)所不能接受的。
子系統(tǒng)的內(nèi)部方法直接暴露給外部調(diào)用,安全性低。
當(dāng)錦囊數(shù)越來越多的時(shí)候,那么Client就需要調(diào)用更多錦囊類來實(shí)現(xiàn),這就會(huì)增加Client的實(shí)現(xiàn)難度,維護(hù)更加困難。
四、趙云協(xié)助用妙計(jì)(門面模式)
諸葛亮能夠想到應(yīng)對(duì)之策,當(dāng)然也會(huì)考慮到讓誰和如何實(shí)施這三個(gè)錦囊才能夠讓劉備順利化險(xiǎn)為夷。綜合上面劉備親自實(shí)施錦囊妙計(jì)帶來的問題,安排趙云保管錦囊并在適當(dāng)?shù)臅r(shí)機(jī)協(xié)助實(shí)施才是上上之策。
1.UML實(shí)現(xiàn)
增加了一個(gè)ZhaoYunFacadee類,負(fù)責(zé)對(duì)錦囊實(shí)施過程進(jìn)行封裝,然后高層模塊只要和它有交互就成。
2.增加的代碼模塊
①趙云充當(dāng)門面
public class ZhaoYunFacade {
//妙計(jì)一
private Strategy strategyOne=new StrategyOne();
//妙計(jì)二
private Strategy strategyTwo=new StrategyTwo();
//妙計(jì)三
private Strategy strategyThree=new StrategyThree();
//三妙計(jì)統(tǒng)一讓趙云協(xié)助實(shí)施
public void carryOut(){
//劉備一行人到達(dá)南徐的時(shí)候,打開第一個(gè)錦囊
strategyOne.carryOut();
//周瑜和孫權(quán)通過計(jì)謀使劉備沉迷在溫柔鄉(xiāng)無法自拔
strategyTwo.carryOut();
//周瑜看計(jì)謀不行,出兵攔殺劉備
strategyThree.carryOut();
}
}
劉備在遇到困難的時(shí)候,只要讓趙云根據(jù)諸葛亮的錦囊進(jìn)行處理,這多簡(jiǎn)單,Client減少了很多工作。
②Client
public class Client {
public static void main(String[] args) {
//劉備遇到困難,只要通過趙云按照錦囊實(shí)施,就可化險(xiǎn)為夷
ZhaoYunFacade zhaoYunFacade=new ZhaoYunFacade();
zhaoYunFacade.carryOut();;
}
}
輸出的結(jié)果為:
//劉備一行人到達(dá)南徐的時(shí)候,打開第一個(gè)錦囊
見喬國老,并把劉備娶親的事情搞得東吳人盡皆知。
//周瑜和孫權(quán)通過計(jì)謀使劉備沉迷在溫柔鄉(xiāng)無法自拔
用謊言(曹操打荊州)騙泡在溫柔鄉(xiāng)里的劉備回去。
//周瑜看計(jì)謀不行,出兵攔殺劉備
讓孫夫人擺平東吳的追兵。
運(yùn)行結(jié)果是相同的。場(chǎng)景類簡(jiǎn)化了很多,只要與ZhaoYunFacade交互就成了,其他的什么都不用管,什么時(shí)候使用錦囊、怎么用都不用管,只要調(diào)用ZhaoYunFacade提供的方法,就可以得到想要的妙計(jì),這種方式不僅簡(jiǎn)單,而且擴(kuò)展性還非常好,同時(shí)不改變子系統(tǒng)對(duì)外暴露的接口、方法,只改變內(nèi)部的處理邏輯,其他兄弟模塊的調(diào)用產(chǎn)生了不同的結(jié)果。
3.兩種方案的程序結(jié)構(gòu)圖
- 沒有采用門面模式
- 采用門面模式
總的來說,門面對(duì)象是外界訪問子系統(tǒng)內(nèi)部的唯一通道,不管子系統(tǒng)內(nèi)部是多么雜亂無章。
五、門面模式的介紹
1.門面模式的定義
門面模式(Facade Pattern)也叫做外觀模式。要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對(duì)象進(jìn)行。門面模式提供一個(gè)高層次的接口,使得子系統(tǒng)更易于使用。
2.中介模式的角色介紹
Facade門面角色
客戶端可以調(diào)用這個(gè)角色的方法。此角色知曉子系統(tǒng)的所有功能和責(zé)任。一般情況下,本角色會(huì)將所有從客戶端發(fā)來的請(qǐng)求委派到相應(yīng)的子系統(tǒng)去,也就說該角色沒有實(shí)際的業(yè)務(wù)邏輯,只是一個(gè)委托類。subsystem子系統(tǒng)角色
可以同時(shí)有一個(gè)或者多個(gè)子系統(tǒng)。每一個(gè)子系統(tǒng)都不是一個(gè)單獨(dú)的類,而是一個(gè)類的集合。子系統(tǒng)并不知道門面的存在。對(duì)于子系統(tǒng)而言,門面僅僅是另外一個(gè)客戶端而已。
3.門面模式的使用場(chǎng)景
為一個(gè)復(fù)雜的模塊或子系統(tǒng)提供一個(gè)供外界訪問的接口。
為降低個(gè)人代碼質(zhì)量對(duì)整體項(xiàng)目的影響風(fēng)險(xiǎn),只能在指定的子系統(tǒng)中開發(fā),然后再提供門面接口進(jìn)行訪問操作。
子系統(tǒng)相對(duì)獨(dú)立——外界對(duì)子系統(tǒng)的訪問只要黑箱操作即可。