設計模式之策略模式

定義

定義了算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化不會影響到使用算法的用戶。

if…else…

類型

行爲型

適用場景

①、系統有很多類,而它們的區別僅僅在於它們的行爲不同。
②、一個系統需要動態地在幾種算法中選擇一種。

優缺點

優點:
①、開閉原則
②、避免使用多重條件轉移語句
③、提高算法的保密性和安全性

缺點:
①、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類
②、 產生很多策略類

代碼實現

案例:電商網站經常會在不同的節日搞不同的促銷活動,例如:滿減、立減、返現等等。根據這個場景來使用策略模式實現。
首先創建一個促銷策略的接口

public interface PromotionStrategy {

    /**
     * 促銷
     */
    void doPromotion();
}

然後,分別創建不同促銷策略的實現類。
返現促銷

public class FanXianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("返現促銷,返回的金額存放到用戶的餘額中");
    }
}

立減促銷

public class LiJianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("立減促銷,課程的價格直接減去配置的價格");
    }
}

滿減促銷

public class ManJianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("滿減促銷,滿100減50");
    }
}

無促銷活動

public class EmptyPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("無促銷策略");
    }
}

促銷策略有了,還需要創建具體的促銷活動

public class PromotionActivity {

    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void execute() {
        promotionStrategy.doPromotion();
    }
}

創建測試類

public class MainTest {

    public static void main(String[] args) {

        PromotionActivity promotionActivity = null;
        // 前臺傳過來的標誌
        String PromotionKey = "LiJian";

        if (StringUtils.equals(PromotionKey, "LiJian")) {
            // 京東618立減
            promotionActivity = new PromotionActivity(new LiJianPromotionStrategy());
        } else if (StringUtils.equals(PromotionKey, "ManJian")) {
            // 雙11 滿減
            promotionActivity = new PromotionActivity(new ManJianPromotionStrategy());
        } else {
            promotionActivity = new PromotionActivity(new EmptyPromotionStrategy());
        }
        promotionActivity.execute();
    }
}

輸出結果:

C:\android\java\jdk1.8\bin\java.exe
立減促銷,課程的價格直接減去配置的價格

基本上策略模式就實現了,但是查看上面的代碼,在開放立減策略或者其他策略的時候,都需要重新new一個當前的策略,這並不是我們所需要的。爲了消除if…else…以及避免多次重複的創建對象,結合工廠設計模式對當前的代碼進行改進。
首先創建一個策略工廠

public class PromotionStrategyFactory {

    /**
     * 存放所有促銷策略
     */
    private static final Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
    /**
     * 沒有促銷
     */
    private static final EmptyPromotionStrategy EMPTY_PROMOTION_STRATEGY = new EmptyPromotionStrategy();

    private interface PromotionKey {
        String LIJian = "LiJian";
        String FanXian = "FanXian";
        String ManJian = "ManJian";
    }

    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FanXian, new FanXianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJian, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.ManJian, new ManJianPromotionStrategy());
    }

    private PromotionStrategyFactory() {
    }

    public static PromotionStrategy getPromotionStrategy(String PromotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(PromotionKey);
        return promotionStrategy == null ? EMPTY_PROMOTION_STRATEGY : promotionStrategy;
    }
}

這裏使用Map來存放所有的促銷策略,並在應用初始化時,就將策略放入Map集合中,並提供獲取策略的方法。
編寫測試類

    @Test
    public void testMethod2(){
        // 前臺傳過來的標誌
        String PromotionKey = "ManJian";
        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(PromotionKey));
        promotionActivity.execute();
    }

輸出結果:

C:\android\java\jdk1.8\bin\java.exe 
滿減促銷,滿100減50

這樣就將if…else…消除了,並且簡化了代碼,使得代碼的業務邏輯變得優雅。

相關源碼

1. Jdk中的Comparator比較器。
2. Spring中的org.springframework.core.io.Resource。
3. Spring中bean初始化使用的InstantiationStrategy。

參考鏈接
https://coding.imooc.com/learn/list/270.html

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