從未這麼明白的設計模式(四):策略模式


本文原創地址:jsbintask的博客(食用效果最佳),轉載請註明出處!

前言

策略模式是一種行爲模式,它用以運行時動態的改變類的行爲,通過將一系列類似的算法封裝成不同的類來達到目的,可以有效減少代碼中if else的冗餘。它實現的關鍵是面向接口接口編程以及有一個算法切換者。它的優點是擴展性良好,可以自由切換策略。

栗子

週末天氣不錯,小明準備去爬武功山,於是他請教它的出行助手應該選擇怎樣的工具去目的地才能讓他最大化週末的快樂。於是它的出行助手開始了一段計算,操作。。。最終。。。

抽象

針對上面的案例,重點在於出行助手如何幫小明選擇出行工具,這恰好可以對應我們一開始說的需要封裝的算法,並且能夠隨意切換,於是我們可以得出下面的uml類圖:


小明通過使用出行助手來選擇不同的交通工具。而出行助手內部則通過代理TravelStrategy接口來切換不同的出行算法。

實現

首先定義出行接口TravelStrategy

@FunctionalInterface
public interface TravelStrategy {
    void travel();
}

接着實現不同的出行算法,此處有BikeTravelStrategy, FootTravelStrategy, CarTravelStrategy

@Slf4j
public class BikeTravelStrategy implements TravelStrategy {
    @Override
    public void travel() {
      log.info("自行車騎行半小時,行程18公里,感覺卡路里在燃燒!");
    }
}
============================================================
@Slf4j
public class FootTravelStrategy implements TravelStrategy {

    @Override
    public void travel() {
        log.info("徒步旅行半小時,行走5公里,可以好好欣賞周邊景色");
    }
}
============================================================
@Slf4j
public class CarTravelStrategy implements TravelStrategy {
    @Override
    public void travel() {
      log.info("自駕旅行半小時,行程40公里,感覺時間走的真慢。");
    }
}

接着就需要實現出行助手類:TravelService,它內部通過代理TravelStategy來切換不同的策略:

public class TravelService {
    private TravelStrategy travelStrategy;

    public void chooseTravelStrategy(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    public void doTravel() {
        this.travelStrategy.travel();
    }
}

最後,編寫一個測試類:

@Slf4j
public class App {
    public static void main(String[] args) {
        System.out.println("天氣不錯,小明準備出門旅行,它帶上了它的旅行助手'TravelService'來幫它制定出行策略.");
        TravelService travelService = new TravelService();

        System.out.println("'TravelService': 天氣不錯,您可以選擇徒步出行");
        travelService.chooseTravelStrategy(new FootTravelStrategy());
        travelService.doTravel();

        System.out.println("'TravelService': 2小時後可能轉小雨,建議您選擇自行車加快形成,鍛鍊身體!");
        travelService.chooseTravelStrategy(new BikeTravelStrategy());
        travelService.doTravel();

        System.out.println("'TravelService': 半小時後會有暴雨,建議您選擇自駕汽車去目的地.");
        travelService.chooseTravelStrategy(new CarTravelStrategy());
        travelService.doTravel();

        System.out.println("'TravelService': 天氣已經好轉,您可以隨意選擇出行方式。");
        travelService.chooseTravelStrategy(() -> {
            log.info("騎行摩托車開始,半小時形成30公里。刺激!");
        });

        System.out.println("'TravelService': 您已到達目的地.");
    }
}

注意上面的關鍵代碼爲TravelService根據不同的天氣選擇了不同的出行策略。


根據結果我們可以知道我們切換了三次不同的策略,並且使用lambda表達式添加了一個匿名策略。

總結

使用策略模式的關鍵在於面向接口編程,並且有一個全局切換策略的輔助類,它的優點在於擴展性良好,算法可以自由切換動態改變類的行爲。
而它的缺點也很明顯:策略類過多會導致“類爆炸“,並且所有的策略類都需要向外暴露。 所以使用時如果策略過多可以考慮使用混合模式,配合其它模式一起使用。

關注我,這裏只有乾貨!

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