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