設(shè)計(jì)模式詳解——命令、代理、策略模式

前言
今天我們主要來看三種設(shè)計(jì)模式,他們分別是命令模式、代理模式和策略模式。廢話少說,下面我們直接開始吧!
設(shè)計(jì)模式
命令模式
命令模式簡單來說,就是將一組操作整合成一個(gè)通用的命令,然后通過一個(gè)通用的執(zhí)行器來執(zhí)行的一種設(shè)計(jì)模式,這種設(shè)計(jì)模式也是為了更好地實(shí)現(xiàn)代碼的解耦。
這種設(shè)計(jì)模式就類似于一個(gè)遙控器,遙控器上的每一個(gè)按鈕都對(duì)應(yīng)一個(gè)命令,我們不需要關(guān)心命令內(nèi)部執(zhí)行流程,只需要按下(執(zhí)行)這個(gè)按鈕,然后相關(guān)命令就會(huì)被執(zhí)行。
這么說還是有點(diǎn)抽象,下面我們通過一個(gè)簡單的示例來演示下命令模式的用法。
代碼都很簡單,對(duì)于代碼這里就不詳細(xì)說明了,各位小伙伴要關(guān)注的是代碼的設(shè)計(jì),以及他所達(dá)到的解耦效果。
要執(zhí)行命令的對(duì)象
public?class?Light?{
????public?void?on()?{
????????System.out.println("開燈了");
????}
????public?void?off()?{
????????System.out.println("關(guān)燈了");
????}
}
命令接口
public?interface?Command?{
????void?execute();
}
命令實(shí)現(xiàn)
關(guān)燈命令
public?class?LightOffCommand?implements?Command?{
????Light?light;
????public?LightOffCommand(Light?light)?{
????????this.light?=?light;
????}
????@Override
????public?void?execute()?{
????????light.off();
????}
}
開燈命令
public?class?LightOnCommand?implements?Command?{
????Light?light;
????public?LightOnCommand(Light?light)?{
????????this.light?=?light;
????}
????@Override
????public?void?execute()?{
????????light.on();
????}
}
命令執(zhí)行(控制層)
public?class?SimpleRemoteControl?{
????Command?command;
????public?SimpleRemoteControl()?{
????}
????public?void?setCommand(Command?command)?{
????????this.command?=?command;
????}
????public?void?buttonWasPressed()?{
????????command.execute();
????}
}
測試代碼
public?class?CommandTest?{
????@Test
????public?void?testCommand()?{
????????//?創(chuàng)建控制器實(shí)例
????????SimpleRemoteControl?control?=?new?SimpleRemoteControl();
????????//?創(chuàng)建命令執(zhí)行對(duì)象實(shí)例
????????Light?light?=?new?Light();
????????//?創(chuàng)建命令實(shí)例
????????LightOnCommand?onCommand?=?new?LightOnCommand(light);
????????LightOffCommand?offCommand?=?new?LightOffCommand(light);
????????//?開燈
????????//?設(shè)置命令
????????control.setCommand(onCommand);
????????//?執(zhí)行命令
????????control.buttonWasPressed();
????????//?關(guān)燈操作
????????control.setCommand(offCommand);
????????control.buttonWasPressed();
????}
}
運(yùn)行結(jié)果

如果各位小伙伴如果用過struts框架的話,應(yīng)該對(duì)這個(gè)設(shè)計(jì)模式不陌生,因?yàn)樵?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">struts的業(yè)務(wù)控制層中,命令模式被廣泛應(yīng)用。
優(yōu)點(diǎn)
關(guān)于命令模式的好處,想必各位小伙伴都已經(jīng)看出來了:它實(shí)現(xiàn)了控制層與具體對(duì)象之間的耦合關(guān)系,當(dāng)我們具體的業(yè)務(wù)對(duì)象發(fā)生變化時(shí),我們只需要調(diào)整其所對(duì)應(yīng)的命令實(shí)現(xiàn)類即可,而不需要調(diào)整控制層相關(guān)代碼,即提高了系統(tǒng)的可擴(kuò)展性,又保證了它的健壯性,是不是美滋滋呢!
要點(diǎn)
命令模式將發(fā)出請(qǐng)求的對(duì)象和執(zhí)行請(qǐng)求的對(duì)象解耦 在被解耦的兩者之間是通過命令對(duì)象進(jìn)行溝通的。命令對(duì)象封裝了接收者和一個(gè)或一組動(dòng)作 調(diào)用者通過調(diào)用命令對(duì)象的 execute()(方法名可以自己起)發(fā)出請(qǐng)求,這會(huì)使得接受者的動(dòng)作被調(diào)用調(diào)用者可以接受命令當(dāng)做參數(shù),甚至在運(yùn)行時(shí)動(dòng)態(tài)地進(jìn)行 命令可以支持撤銷,做法是實(shí)現(xiàn)一個(gè) undo()方法(也可以自定義)來回到execute()被執(zhí)行前的狀態(tài)宏命令是命令的一種簡單延伸,允許調(diào)用多個(gè)命令,宏方法也可以支持撤銷。 實(shí)際操作時(shí),很常見使用“聰明”命令對(duì)象,也就是直接實(shí)現(xiàn)了請(qǐng)求,而不是將工作委托給接收者 命令也可以用來實(shí)現(xiàn)日志和事務(wù)系統(tǒng)
代理模式
我發(fā)現(xiàn)關(guān)于代理模式的內(nèi)容還是比較多的,考慮到篇幅和時(shí)間,我們今天先說下它的要點(diǎn),同時(shí)由于之前我在分享手寫rpc框架內(nèi)容的時(shí)候已經(jīng)展示過動(dòng)態(tài)代理的相關(guān)用法了,所以今天暫時(shí)先不展開講,等后面把這塊內(nèi)容徹底梳理清楚之后,我們?cè)賮砝^續(xù)分享。
關(guān)于手寫rpc框架中動(dòng)態(tài)代理的內(nèi)容,可以移步到這里看下:
要點(diǎn)
代理模式為另一個(gè)對(duì)象提供代表,以便控制客戶對(duì)對(duì)象的訪問,管理訪問的方式有許多種 遠(yuǎn)程代理管理客戶和遠(yuǎn)程對(duì)象之間的交互 虛擬代理控制訪問實(shí)例化開銷大的對(duì)象 保護(hù)代理基于調(diào)用者控制對(duì)象方法的訪問 代理模式有許多變體,例如:緩存代理、同步代理、防火墻代理和寫入時(shí)復(fù)制代理 代理在結(jié)構(gòu)上類似裝飾者,但是目的不同。裝飾是模式為對(duì)象加上行為,而代理則是控制訪問 java內(nèi)置的代理支持,可以根據(jù)需要建立動(dòng)態(tài)代理,并將所有調(diào)用分配到所選的處理器和其他的包裝者一樣,代理會(huì)造成你的設(shè)計(jì)中類的數(shù)目增加。
策略模式
關(guān)于策略模式,我們前幾天剛分享了一篇與之相關(guān)的應(yīng)用內(nèi)容,各位小伙伴可以回顧下:
策略模式主要是為了優(yōu)化代碼中的邏輯問題,特別是在有多種算法相似的情況下,使用 if...else 所帶來的復(fù)雜和難以維護(hù)的問題。
策略這個(gè)詞,我們?cè)谌粘I钪幸矔?huì)經(jīng)常用到,意思也基本上一致,這里的策略模式就是我們做事策略思維在軟件開發(fā)中的應(yīng)用。
應(yīng)用實(shí)例
諸葛亮的錦囊妙計(jì),每一個(gè)錦囊就是一個(gè)策略。 旅行的出游方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個(gè)策略。 JAVA AWT中的LayoutManager
使用場景
如果在一個(gè)系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為。
一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。
如果一個(gè)對(duì)象有很多的行為,如果不用恰當(dāng)?shù)哪J?,這些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)。
實(shí)例代碼
下面是數(shù)字加減的策略模式實(shí)現(xiàn),各位小伙伴可以試著從代碼中理解下策略模式。
策略接口
public?interface?Strategy?{
???int?doOperation(int?num1,?int?num2);
}
加法策略實(shí)現(xiàn)
public?class?OperationAdd?implements?Strategy{
???@Override
???public?int?doOperation(int?num1,?int?num2)?{
??????return?num1?+?num2;
???}
}
減法策略實(shí)現(xiàn)
public?class?OperationSubtract?implements?Strategy{
???@Override
???public?int?doOperation(int?num1,?int?num2)?{
??????return?num1?-?num2;
???}
}
策略控制器
public?class?StrategyControl?{
???private?Strategy?strategy;
?
???public?StrategyControl(Strategy?strategy){
??????this.strategy?=?strategy;
???}
?
???public?int?executeStrategy(int?num1,?int?num2){
??????return?strategy.doOperation(num1,?num2);
???}
}
測試代碼
public?class?StrategyPatternDemo?{
???public?static?void?main(String[]?args)?{
??????StrategyControl?control?=?new?StrategyControl(new?OperationAdd());????
??????System.out.println("10?+?5?=?"?+?control.executeStrategy(10,?5));
?
??????control?=?new?StrategyControl(new?OperationSubtract());??????
??????System.out.println("10?-?5?=?"?+?control.executeStrategy(10,?5));
???}
}
優(yōu)點(diǎn)
策略模式的優(yōu)點(diǎn)也很明顯,當(dāng)我們的算法策略發(fā)生變動(dòng)時(shí),我們只需要增加新的策略即可,而不需要修改策略實(shí)現(xiàn)之外的代碼,代碼的可擴(kuò)展性又得到了極大的提升。
總結(jié)
好了,關(guān)于這三種設(shè)計(jì)模式,我們暫時(shí)就先說這么多。
從我們總結(jié)的設(shè)計(jì)模式的優(yōu)點(diǎn)來看,基本上所有的設(shè)計(jì)模式,都是為了提升我們系統(tǒng)的可擴(kuò)張性,同時(shí)降低系統(tǒng)的耦合性,而且一定程度上減少了重復(fù)代碼,當(dāng)然也是我們要學(xué)習(xí)和應(yīng)用設(shè)計(jì)模式的意義。
最后,大家需要著重關(guān)注的是策略模式和命令模式,這兩種設(shè)計(jì)模式是我們?cè)跇I(yè)務(wù)開發(fā)中最可能能用到的,特別是策略模式,至于代理模式,我目前能想到的就是框架開發(fā)了,其他的我暫時(shí)還真想不到。
- END -

