小白寫了一堆if-else,大神實在看不下去了,居然用策略模式直接擺平了

這裏涉及到一個關鍵詞:策略模式,那麼到底什麼是策略模式呢?本文就來好好給你們講講策略模式,你們能夠帶着以下幾個問題來閱讀本文:算法

  1. 如何經過策略模式優化業務邏輯代碼(能夠根據本身從事的工做思考)
  2. 使用策略模式優化if-else,會不會帶來什麼反作用呢?
  3. 實現策略模式是否有更好的方式呢?

1. 策略模式如何優化代碼解構

要會帶這個問題,須要先弄清楚策略模式的定義,首先來看策略模式的教科書定義:數據庫

策略模式(Strategy Pattern):定義一系列算法,將每個算法封裝起來,並讓它們能夠相互替換。 策略模式讓算法獨立於使用它的客戶而變化,也稱爲政策模式(Policy)。 策略模式是一種對象行爲型模式。app

這裏的算法其實就是業務邏輯,爲了更形象,乾脆將其理解爲一個函數。其實這個定義的基本意思就是說,根據策略選擇要執行的函數,而每個策略都會有一個標識,能夠稱爲key。而當前策略要執行的函數,能夠稱爲value,其實就是使用key尋找value,而後執行vlaue的過程。也就是說,一個key對應一個value,從這層意思上理解,就是if-else要乾的事。ide

那麼策略模式到底優化了什麼呢?函數

其實策略模式的核心思想與 if else一模一樣,根據不一樣的key動態的找到不一樣的業務邏輯(要執行的函數)。那它就只是如此嗎?測試

實際上,咱們口中的策略模式其實就是在代碼結構上調整,用接口+實現類+分派邏輯來使代碼結構可維護性更好。優化

通常教科書上講到接口與實現類就結束了,其餘博客上會帶上說起分派邏輯。這裏就不囉嗦了。如今總結一下:即便用了策略模式,全部的業務邏輯同樣都少不了,改寫的仍然須要寫。到邏輯分派的時候,仍是變相的if-else。而策略模式的優化點是抽象了出了接口,將業務邏輯封裝成一個一個的實現類,任意地替換。在複雜場景(業務邏輯較多)時比直接 使用if-else 更好維護。ui

2. 使用策略模式優化if-else,會不會帶來什麼反作用呢?

我估計確定會有不少同窗這麼想:個人業務邏輯就幾行,你給我整一大堆類定義?有必要這麼麻煩嗎?我看具體的業務邏輯還須要去不一樣的類中,簡單點不香嗎!spa

其實這裏的不滿也正是策略模式的缺點:設計

(1) 策略類會增多 
(2) 業務邏輯分散到各個實現類中,並且沒有一個地方能夠俯視整個業務邏輯

針對傳統策略模式的缺點,在這分享一個實現思路,這個思路已經幫咱們團隊解決了多個複雜if else的業務場景,理解上比較容易,在技術上要使用到Java8的特性:Map與函數式接口。

廢話少說,直接看代碼:

先看兩個方法:

  1. proce***esult() :使用if-else的方法
  2. processPolicyResult():使用策略模式的方法。在該方法中事先在Map中定義好了「判斷條件」與「業務邏輯」的映射關係,具體看代碼吧!
/**
 * 策略模式演示類
 */
public class MyService {

    /**
     * 使用if-else的解決方案
     */
    public String proce***esult(String key) {
        if ("checkvalue1".equals(key)) {
            return "business logic1";   
        } else if ("checkvalue2".equals(key)) {
            return "business logic2";
        }else if ("checkvalue3".equals(key)) {
            return "business logic3";
        }else if ("checkvalue4".equals(key)) {
            return "business logic4";
        }else if ("checkvalue5".equals(key)) {
            return "business logic5";
        }else if ("checkvalue6".equals(key)) {
            return "business logic6";
        }else if ("checkvalue7".equals(key)) {
            return "business logic7";
        }else if ("checkvalue8".equals(key)) {
            return "business logic8";
        }else if ("checkvalue9".equals(key)) {
            return "business logic9";
        }
        return "error;
    }

    /**
     * 用於業務邏輯分派Map
     * Function爲函數式接口,下面代碼中 Function<String, String> 的含義是接收一個String類型的變量,返回一個String類型的結果
     */
    private Map<String, Function<String, String>> myDispatcher = new HashMap<>();

    /**
     * 使用策略模式的方法
     */

    public void  policyInit() {
        myDispatcher.put("checkvalue1", key -> String.format("business logic1 for %s1", key));
        myDispatcher.put("checkvalue2", key -> String.format("business logic2 for %s2", key));
        myDispatcher.put("checkvalue3", key -> String.format("business logic3 for %s3", key));
        myDispatcher.put("checkvalue4", key -> String.format("business logic4 for %s4", key));
        myDispatcher.put("checkvalue5", key -> String.format("business logic5 for %s5", key));
        myDispatcher.put("checkvalue6", key -> String.format("business logic6 for %s6", key));
        myDispatcher.put("checkvalue7", key -> String.format("business logic7 for %s7", key));
        myDispatcher.put("checkvalue8", key -> String.format("business logic8 for %s8", key));
        myDispatcher.put("checkvalue9", key -> String.format("business logic9 for %s9", key));
    }

    public String processPolicyResult(String key) {
        //從邏輯分派Dispatcher中得到業務邏輯代碼,result變量是一個lambda表達式
        Function<String, String> result = myDispatcher.get(key);
        if (result != null) {
            //執行這段表達式得到String類型的結果
            return result.apply(key);
        }
        return "error";
    }
}

下面是調用代碼:

public class RunPolicy {
    private MyService myService;

    public String test(String key) {
        return myService.processPolicyResult(order);
    }
}

從這段代碼中能夠看到不少好處,例如:

(1)在policyInit()方法中直觀地看到「判斷條件」與「業務邏輯」的映射關係;
(2)不須要單獨定義接口與實現類,直接使用現有的函數式接口便可;

3. 策略模式在真實場景中的應用

可能有的同窗會說,個人條件判斷可能很是複雜,而前面的案例只有一個條件判斷(key),其實這就和數據庫中經過單個字段做爲索引,仍是使用複合索引(多個字段共同組成索引)的問題。咱們也能夠用複合條件來實現策略模式,上代碼:

/**
 * 策略模式類
 */
public class PolicyService {

    private Map<String, Function<String, String>> myDispatcherMulti = new HashMap<>();

    /**
     * 初始化 業務邏輯分派Map 其中value 存放的是 lambda表達式
     */
    @PostConstruct
    public void dispatcherMuitInit() {
        myDispatcherMulti.put("key_order1", key -> String.format("business logic1 for %s", key));
        myDispatcherMulti.put("key_order2_order3", key -> String.format("business logic2 for %s", key));
        myDispatcherMulti.put("key_order1_order2_order3", key -> String.format("business logic3 for %s", key));
    }

    public String processMuti(String key, int level) {
        //根據level獲取不一樣的key
        String dKey = getDispatcherKey(key, level);

        Function<String, String> result = myDispatcherMuti.get(dKey);
        if (result != null) {
            //執行這段表達式得到String類型的結果
            return result.apply(key);
        }
        return "error";
    }

    /**
     * 根據level生成不一樣層次的key
     */
    private String getDispatcherKey(String key, int level) {
        StringBuilder k = new StringBuilder("key");
        for (int i = 1; i <= level; i++) {
            k.append("_" + order + i);
        }
        return k.toString();
    }
}

/**
 * 測試代碼
 */
public class  TestPolicyMulti {

    private PolicyService policyService;

    public String test(String key, int level) {
        return policyService.processMuti(key, level);
    }
}

在這段代碼中,key是知足必定規則的複合條件,只要設計好key的生成規則就一切ok!

可能還會有不少同窗問,個人業務邏輯有不少行,在dispatcherMuitInit()方法的Map中直接寫不會很長嗎?直接寫固然長了,咱們能夠抽象出一個服務類專門放業務邏輯,而後在定義中調用它就能夠了,代碼以下:

/**
 * 專門放業務邏輯的服務類
 */
public class ServiceUnit {

    public String task1(String key) {
        return "業務邏輯1";
    }
    public String task2(String key) {
        return "業務邏輯2";
    }
     public String task3(String key) {
        return "業務邏輯3";
    }
     public String task4(String key) {
        return "業務邏輯4";
    }
}
/**
 * 使用策略模式的類
 */
public class PolicyService {
    private ServiceUnit serviceUnit;

    private Map<String, Function<String, String>> myDispatcher = new HashMap<>();

    /**
     * 初始化規則映射
     */
    public void dispatcherInit() {
        myDispatcher.put("key_order1", key -> serviceUnit.task1(key));
        myDispatcher.put("key_order1_order2", key -> serviceUnit.task2(key)));
        myDispatcher.put("key_order1_order2_order3", key -> serviceUnit.task3(key));
        myDispatcher.put("key_order1_order2_order3_order4", key -> serviceUnit.task4(key));
    }

    public String process(String key, int level) {
        // 根據level生成對應的key
        String dKey = getDispatcherKey(key, level);

        Function<String, String> result = myDispatcher.get(dKey);
        if (result != null) {
            //執行這段表達式得到String類型的結果
            return result.apply(order);
        }
        return "error";
    }

    /**
     * 根據level生成對應的key
     */
    private String getDispatcherKey(String key, int level) {
        StringBuilder k = new StringBuilder("key");
        for (int i = 1; i <= level; i++) {
            k.append("_" + order + i);
        }
        return k.toString();
    }
}

總結:

  1. 如何經過策略模式優化業務邏輯代碼(能夠根據本身從事的工做思考)
    抽象了出了接口,將業務邏輯封裝成的實現類,任意地替換。在複雜場景(業務邏輯較多)時比直接 使用if-else 更好維護。

  2. 使用策略模式優化if-else,會不會帶來什麼反作用呢?

其實使用策略模式大多數時候會帶來不少好處,不過也會有一些不足的:
(1)策略類比較多;
(2)業務邏輯分散到各個實現類中,並且沒有一個地方能夠俯覽整個業務邏輯;

  1. 實現策略模式是否有更好的方式呢?

能夠用函數函數式接口實現業務邏輯,這樣能夠更直觀觀察策略和執行邏輯的關係。

相關文章
相關標籤/搜索