[設計模式] 行爲型:策略模式(Strategy Pattern)

什麼是策略模式

策略,就是解決問題的具體方法。針對同一個問題的不同條件,可以有多種不同的解決方法。

比如,外出旅行,可選的出行方式有:汽車(省內旅行)、火車(國內旅行)、飛機(國際旅行)。每一種出行方式都是一種具體的策略,各自都有對應的選擇條件。

如果把這個場景用代碼表示出來,最容易想到的應該就是用if...else...來實現。但是,這在編程老鳥眼裏是有問題的,後期擴展性不佳。

簡單解釋下爲什麼擴展性不佳,隨着場景的豐富,策略選擇條件可能會更復雜,也可能會增加新的策略。比如說,省內旅行不一定都選擇汽車,如果坐火車更快,那就是更好的選擇;再比如說,要去太空旅行,汽車、火車、飛機都無法滿足,就得考慮新增“飛船”的選項了。

每當變化發生的時候,if...else...就得跟着變化,試想一下,在條件複雜、交通工具很多的場景下,if...else...會是怎樣的臃腫!

這樣的代碼看着不爽,後期自己看邏輯可能也會懵逼,交接出去後別人大概率還會罵你。

爲了避免臃腫的if...else...,可以選用策略模式,考慮用“面向對象思想”解決問題。兩者考慮問題的思路稍有不同:

  1. if...else...思路:我要旅行,現在需要選擇一種交通工具,省內旅行就坐汽車,國內旅行就坐火車,國際旅行就坐飛機,選擇好以後,出發去旅行
  2. 策略模式思路:我要旅行,去找個導遊,幫我選擇交通工具,選擇好以後,出發去旅行

兩者不同之處:策略選擇誰去做?

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();// 旅行者出發去旅行
}

由於場景簡單,這段代碼看着也挺簡潔。但是,這段場景代碼還是耦合了兩個邏輯:

  1. 自身旅行邏輯:有旅行想法,選擇出行工具,出發旅行
  2. 交通選擇邏輯:省內旅行選擇汽車,國內旅行選擇火車,國際旅行選擇飛機

如果是現實生活中的自由旅行,這就是很正常的事情,所有過程細節都需要旅行者自己考慮選擇清楚。

作爲一個就想旅遊放鬆幾天的旅行者,事無鉅細都要考慮,也是一件蠻累的事情。

那就找個導遊,減輕一些旅行者的工作,讓旅行者專注於旅行本身,交通工具的選擇就交給專業的導遊吧。

這就是策略模式要做的事情,專業的策略選擇交給專業的對象去做。

定義一個策略決策者,也就是導遊:

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...逐漸臃腫到人類思維都覺的複雜時,就該考慮用策略模式重構它了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章