什麼是策略模式
策略,就是解決問題的具體方法。針對同一個問題的不同條件,可以有多種不同的解決方法。
比如,外出旅行,可選的出行方式有:汽車(省內旅行)、火車(國內旅行)、飛機(國際旅行)。每一種出行方式都是一種具體的策略,各自都有對應的選擇條件。
如果把這個場景用代碼表示出來,最容易想到的應該就是用if...else...
來實現。但是,這在編程老鳥眼裏是有問題的,後期擴展性不佳。
簡單解釋下爲什麼擴展性不佳,隨着場景的豐富,策略選擇條件可能會更復雜,也可能會增加新的策略。比如說,省內旅行不一定都選擇汽車,如果坐火車更快,那就是更好的選擇;再比如說,要去太空旅行,汽車、火車、飛機都無法滿足,就得考慮新增“飛船”的選項了。
每當變化發生的時候,if...else...
就得跟着變化,試想一下,在條件複雜、交通工具很多的場景下,if...else...
會是怎樣的臃腫!
這樣的代碼看着不爽,後期自己看邏輯可能也會懵逼,交接出去後別人大概率還會罵你。
爲了避免臃腫的if...else...
,可以選用策略模式,考慮用“面向對象思想”解決問題。兩者考慮問題的思路稍有不同:
if...else...
思路:我要旅行,現在需要選擇一種交通工具,省內旅行就坐汽車,國內旅行就坐火車,國際旅行就坐飛機,選擇好以後,出發去旅行- 策略模式思路:我要旅行,去找個導遊,幫我選擇交通工具,選擇好以後,出發去旅行
兩者不同之處:策略選擇誰去做?
在if...else...
下,旅行者不僅提出條件,還要做出交通選擇。
在策略模式下,旅行者只需提出條件,交通策略交由導遊選擇。
設計與實現
無論是用if...else...
,還是用策略模式,代碼中都有一些固定不變的對象定義:一個要旅行者,三種交通工具,汽車、火車、飛機。
public interface Transport { // 出行工具的抽象
void go();// 出行
}
public class Car implements Transport { // 汽車
@Override
public void go() { System.out.println("汽車出行"); }
}
public class Train implements Transport { // 火車
@Override
public void go() { System.out.println("火車出行"); }
}
public class Airplane implements Transport { // 飛機
@Override
public void go() { System.out.println("飛機出行"); }
}
public class Passenger { // 乘客
private Integer condition; // 出行條件:1-省內旅行,2-國內旅行,3-國際旅行
private Transport transport; // 出行工具
public Passenger(Integer condition) { this.condition = condition; }
public Integer getCondition() { return condition; }
public void setTransport(Transport transport) { this.transport = transport; }
public void travel() { transport.go(); } // 旅行
}
基本對象類都定義好了,具體場景邏輯用if...else...
實現,如下:
// 具體場景下的策略選擇邏輯
public static void main(String[] args) {
Passenger passenger = new Passenger(1);
if (passenger.getCondition() == 1) { // 省內旅行,選擇汽車
passenger.setTransport(new Car());
} else if (passenger.getCondition() == 2) { // 國內旅行,選擇火車
passenger.setTransport(new Train());
} else if (passenger.getCondition() == 3) { // 國際旅行,選擇飛機
passenger.setTransport(new Airplane());
} else {
System.out.println("非法場景!");
}
passenger.travel();// 旅行者出發去旅行
}
由於場景簡單,這段代碼看着也挺簡潔。但是,這段場景代碼還是耦合了兩個邏輯:
- 自身旅行邏輯:有旅行想法,選擇出行工具,出發旅行
- 交通選擇邏輯:省內旅行選擇汽車,國內旅行選擇火車,國際旅行選擇飛機
如果是現實生活中的自由旅行,這就是很正常的事情,所有過程細節都需要旅行者自己考慮選擇清楚。
作爲一個就想旅遊放鬆幾天的旅行者,事無鉅細都要考慮,也是一件蠻累的事情。
那就找個導遊,減輕一些旅行者的工作,讓旅行者專注於旅行本身,交通工具的選擇就交給專業的導遊吧。
這就是策略模式要做的事情,專業的策略選擇交給專業的對象去做。
定義一個策略決策者,也就是導遊:
public class Guide {
Map<Integer, Transport> map = new HashMap<>(); // 所有的策略條件
public Guide() {
map.put(1, new Car()); // 省內旅行,選擇汽車
map.put(2, new Train()); // 國內旅行,選擇火車
map.put(3, new Airplane()); // 國際旅行,選擇飛機
}
public Transport chooseTransport(Integer condition) { return map.get(condition); }
}
有了這個導遊做決策,旅行者的旅行就會很輕鬆,只需享受旅行本身就好。
public static void main(String[] args) {
Guide guide = new Guide();
Passenger passenger = new Passenger(1); // 旅行者確定出行條件
Transport transport = guide.chooseTransport(passenger.getCondition()); // 導遊選擇交通策略
passenger.setTransport(transport);
passenger.travel();// 出發去旅行
}
這樣的場景代碼是不是看着就很友好?旅行者沒有太多的選擇條件要去思考,只需專心享受旅行就好。
總結
策略模式主要用在選擇複雜的場景中,將複雜業務中“策略選擇”這件事情獨立出來,形成通用組件,可以提高程序後期的維護性與擴展性。
凡事不要絕對化,在簡單場景中,還是儘量優先選用if...else...
,因爲代碼好寫並且直觀,代碼量相對也比較少。
策略模式可以認爲是if...else...
的升級版本,當if...else...
逐漸臃腫到人類思維都覺的複雜時,就該考慮用策略模式重構它了。