這裏涉及到一個關鍵詞:策略模式,那麼到底什麼是策略模式呢?本文就來好好給你們講講策略模式,你們能夠帶着以下幾個問題來閱讀本文:算法
要會帶這個問題,須要先弄清楚策略模式的定義,首先來看策略模式的教科書定義:數據庫
策略模式(Strategy Pattern):定義一系列算法,將每個算法封裝起來,並讓它們能夠相互替換。 策略模式讓算法獨立於使用它的客戶而變化,也稱爲政策模式(Policy)。 策略模式是一種對象行爲型模式。app
這裏的算法其實就是業務邏輯,爲了更形象,乾脆將其理解爲一個函數。其實這個定義的基本意思就是說,根據策略選擇要執行的函數,而每個策略都會有一個標識,能夠稱爲key。而當前策略要執行的函數,能夠稱爲value,其實就是使用key尋找value,而後執行vlaue的過程。也就是說,一個key對應一個value,從這層意思上理解,就是if-else要乾的事。ide
那麼策略模式到底優化了什麼呢?函數
其實策略模式的核心思想與 if else一模一樣,根據不一樣的key動態的找到不一樣的業務邏輯(要執行的函數)。那它就只是如此嗎?測試
實際上,咱們口中的策略模式其實就是在代碼結構上調整,用接口+實現類+分派邏輯來使代碼結構可維護性更好。優化
通常教科書上講到接口與實現類就結束了,其餘博客上會帶上說起分派邏輯。這裏就不囉嗦了。如今總結一下:即便用了策略模式,全部的業務邏輯同樣都少不了,改寫的仍然須要寫。到邏輯分派的時候,仍是變相的if-else。而策略模式的優化點是抽象了出了接口,將業務邏輯封裝成一個一個的實現類,任意地替換。在複雜場景(業務邏輯較多)時比直接 使用if-else 更好維護。ui
我估計確定會有不少同窗這麼想:個人業務邏輯就幾行,你給我整一大堆類定義?有必要這麼麻煩嗎?我看具體的業務邏輯還須要去不一樣的類中,簡單點不香嗎!spa
其實這裏的不滿也正是策略模式的缺點:設計
(1) 策略類會增多 (2) 業務邏輯分散到各個實現類中,並且沒有一個地方能夠俯視整個業務邏輯
針對傳統策略模式的缺點,在這分享一個實現思路,這個思路已經幫咱們團隊解決了多個複雜if else的業務場景,理解上比較容易,在技術上要使用到Java8的特性: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)不須要單獨定義接口與實現類,直接使用現有的函數式接口便可;
可能有的同窗會說,個人條件判斷可能很是複雜,而前面的案例只有一個條件判斷(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(); } }
總結:
如何經過策略模式優化業務邏輯代碼(能夠根據本身從事的工做思考)
抽象了出了接口,將業務邏輯封裝成的實現類,任意地替換。在複雜場景(業務邏輯較多)時比直接 使用if-else 更好維護。
其實使用策略模式大多數時候會帶來不少好處,不過也會有一些不足的:
(1)策略類比較多;
(2)業務邏輯分散到各個實現類中,並且沒有一個地方能夠俯覽整個業務邏輯;
能夠用函數函數式接口實現業務邏輯,這樣能夠更直觀觀察策略和執行邏輯的關係。