公告
如果您是第一次閱讀我的設(shè)計(jì)模式系列文章胧卤,建議先閱讀設(shè)計(jì)模式開篇,希望能得到您寶貴的建議拼岳。
前言
Alice
這個(gè)購買機(jī)器人女友的事情鬧的沸沸揚(yáng)揚(yáng)枝誊,Alice
的爸爸實(shí)在不能同意Alice
這樣胡鬧下去,于是Alice
的爸爸就去了Alice
家(他們平時(shí)不住在一起)惜纸。
無巧不巧的是那天正好Alice
不在家叶撒,只有女友Samu
在家绝骚。于是Alice的爸爸
叫Samu
開門表明身份是Alice的爸爸
,可是Samu
最終仍是拒絕了開門……最后Alice的爸爸
在寒冷的北風(fēng)中站了8個(gè)小時(shí)后痊乾,Alice
回來后 Samu
才開的門皮壁。
正文
Alice的爸爸
:Samu
開開門,我是Alice的爸爸
哪审。
Samu
:無法鑒定身份蛾魄,抱歉無法為你開門。
Alice的爸爸
:我出示我的身份證給你看湿滓,Samu
滴须。(出示了身份證)
Samu
:無法鑒定身份,抱歉無法為你開門叽奥。
Alice的爸爸
:……(吐血中)
……(Alice
回來了)
Alice
:Samu
開開門扔水。
Samu
:歡迎回家,Alice
朝氓!
Alice的爸爸
:……(吐血中)
程序員視角
現(xiàn)在要實(shí)現(xiàn)身份識別驗(yàn)證后開門的功能魔市,起初Alice
并沒有把他爸爸的信息告知Samu
,所以Samu
無法為他開門赵哲。后面Alice
允許Samu
授予他爸爸開門的權(quán)限奴愉。
在本章中不將重心放在權(quán)限層級(如果要考慮權(quán)限相對復(fù)雜壳快,可考慮享元模式),僅考慮如何識別身份后的分支操作 — — 開門或不開門
。
當(dāng)然如果只是IF-ELSE
自然是TOO YOUNG TOO SIMPLE
搭独。
如何實(shí)現(xiàn)
策略模式本質(zhì):分離算法藐守,選擇實(shí)現(xiàn)荸频。
參考狀態(tài)模式 命令模式中的經(jīng)驗(yàn)留晚,單個(gè)命令或狀態(tài)只處理其自身的邏輯“亲睿— — 職責(zé)單一原則
丑勤。
為了保證23個(gè)GOF都使用同一個(gè)GITHUB項(xiàng)目,所以計(jì)劃23個(gè)GOF模式都會(huì)使用同一個(gè)場景“機(jī)器人”作為基礎(chǔ)吧趣,所以故事之間會(huì)有一些關(guān)聯(lián)确封。
延續(xù)前一篇文章“命令行模式”,本次要求能夠接收開門命令再菊,所以需要實(shí)現(xiàn)接口開門命令爪喘。
定義開門命令
public class OpenDoorCommandImpl implements ICommand {
private User user;
private Machine machine;
public OpenDoorCommandImpl(User user, Machine machine) {
this.user = user;
this.machine = machine;
}
@Override
public void excute() {
machine.getStrategy(user).operation();
}
}
同時(shí)為了模擬機(jī)器人管理開門策略,所以在Machine
中作了些許變更纠拔。
public class Machine {
private String name;
public Machine(String name) {
this.name = name;
System.out.println("創(chuàng)建了機(jī)器人 " + name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// 管理了所有的策略(這里是策略接口)
private HashMap<User, IStrategy> map = new HashMap<>();
public void configure(User user, IStrategy strategy) {
map.put(user, strategy);
}
public IStrategy getStrategy(User user) {
return map.get(user);
}
@Override
public String toString() {
return name;
}
}
定義命令接收器
public class OpenDoorCommandReceiver {
private CommandManager invoke = new CommandManager();
private Machine machine;
public OpenDoorCommandReceiver(Machine machine) {
this.machine = machine;
System.out.printf("機(jī)器人%s的接收功能正常開啟%n", machine);
}
public void onReceive(String command, User user) {
System.out.printf("機(jī)器人%s接收到指令:%s秉剑,%s%n", machine, command, user);
invoke.invoke(new OpenDoorCommandImpl(user, machine));
}
}
原先在調(diào)用播放歌曲命令時(shí),使用適配器適配了String類型作為命令參數(shù)稠诲。在本例時(shí)侦鹏,暫時(shí)不做適配器適配開門命令接口诡曙,下一篇文章會(huì)仔細(xì)描述適配器模式。
定義策略的接口:
public interface IStrategy {
void operation();
}
實(shí)現(xiàn)成功開門策略:
public class VerifySuccessStrategy implements IStrategy {
@Override
public void operation() {
System.out.println("驗(yàn)證通過略水,已將門打開");
}
}
實(shí)現(xiàn)失敗開門策略:
public class VerifyFailStrategy implements IStrategy {
@Override
public void operation() {
System.out.println("驗(yàn)證失敗价卤,無法為您開門");
}
}
客戶端調(diào)用測試
public class Client {
public static void main(String[] args) {
User alice = new User("Alice");
User aliceParent = new User("Alice's Parent");
Machine machine = new Machine("Samu");
machine.configure(alice, new VerifySuccessStrategy());
machine.configure(aliceParent, new VerifyFailStrategy());
OpenDoorCommandReceiver receiver = new OpenDoorCommandReceiver(machine);
System.out.println("++aliceParent++");
receiver.onReceive("開門", aliceParent);
System.out.println("--aliceParent--");
System.out.println("++alice++");
receiver.onReceive("開門", alice);
System.out.println("--alice--");
}
}
測試結(jié)果
創(chuàng)建了機(jī)器人 Samu
機(jī)器人Samu的接收功能正常開啟
++aliceParent++
機(jī)器人Samu接收到指令:開門,com.bookbuf.gof23.User@1b6d3586
驗(yàn)證失敗渊涝,無法為您開門
--aliceParent--
++alice++
機(jī)器人Samu接收到指令:開門慎璧,com.bookbuf.gof23.User@28d93b30
驗(yàn)證通過,已將門打開
--alice--
總結(jié)
策略模式的本質(zhì):分離算法跨释,選擇實(shí)現(xiàn)
- 策略模式是一個(gè)比較容易理解和使用的設(shè)計(jì)模式胸私,策略模式是對算法的封裝,它把算法的責(zé)任和算法本身分割開鳖谈,委派給不同的對象管理岁疼。策略模式通常把一個(gè)系列的算法封裝到一系列的策略類里面,作為一個(gè)抽象策略類的子類缆娃。用一句話來說捷绒,就是“準(zhǔn)備一組算法,并將每一個(gè)算法封裝起來贯要,使得它們可以互換”暖侨。
策略模式的優(yōu)點(diǎn)
- 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上* 選擇算法或行為郭毕,也可以靈活地增加新的算法或行為。
- 策略模式提供了管理相關(guān)的算法族的辦法函荣。
- 策略模式提供了可以替換繼承關(guān)系的辦法显押。
- 使用策略模式可以避免使用多重條件轉(zhuǎn)移語句。
策略模式的缺點(diǎn)
- 客戶端必須知道所有的策略類傻挂,并自行決定使用哪一個(gè)策略類乘碑。
- 策略模式將造成產(chǎn)生很多策略類,可以通過使用享元模式在一定程度上減少對象的數(shù)量金拒。
在以下情況下可以使用策略模式:
- 如果在一個(gè)系統(tǒng)里面有許多類兽肤,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對象在許多行為中選擇一種行為绪抛。
一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種资铡。 - 如果一個(gè)對象有很多的行為,如果不用恰當(dāng)?shù)哪J酱甭耄@些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)笤休。
- 不希望客戶端知道復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)症副,在具體策略類中封裝算法和相關(guān)的數(shù)據(jù)結(jié)構(gòu)店雅,提高算法的保密性與安全性政基。