大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心~
最近我在項目中遇到一個需求,就是需要根據一個人的這些條件:
根據不同的這些條件去執行不同的函數,比如:
這種判斷是需要嵌套判斷的,情況非常多,寫起代碼非常麻煩,且可維護性很差,所以我第一時間想到了策略模式來解決,但是發現大部分網上的策略模式方案講解都不太符合我這個需求。
最近我對策略模式又有新的理解,我想通過我自己的方式將這些知識分享給大家。
我理解策略模式就是,在不同的條件下去做不用的事情,并且這些事情是不會互相影響的,我們可以把這些不同的事情封裝起來。
就比如下面的簡單例子,根據 name 的不同的值,去執行不同的代碼:
上面的代碼怎么優化呢?看過一些簡單策略模式的朋友,肯定第一感覺就是使用對象去存儲,其實在這個場景中,完全可以去這么做:
上面的代碼例子是非常簡單的,但是如果是一些比較復雜的場景呢?比如我不止 name 了,我加了 age ,那么這樣的 if 嵌套,你又該如何去用簡單的 map 去解決呢?
有人說,那我這樣去做,不就行了~
是,其實你非要去做也能做,無非就是麻煩點,但是如果我不止 name、age,我又加了 height、weight、username、phone 之類的判斷條件,請問閣下又該如何應對呢?而且是嵌套的哦~
還有一種情況,就是如果我們并不是每一個分支的情況都需要去執行代碼的,比如:
或者哪天我想改變規則了,比如:我想改變一下,只關注 sunshine_lin 的 40歲 情況。
在遇到上述所說這些情況的時候,如果你還以上面的策略模式方案去解決問題,那么解決起來會非常棘手,可維護性也不太高,所以我們應該換一個方案~
大方向上,還是用一個對象去映射,也就是不同條件映射到不同的執行代碼,只不過呢,這個時候我們要把條件換一換,還是剛剛的例子:
換一種思路,我們使用一個集合去當條件,比如像這樣子:
是的,這個所謂的集合就是所有判斷條件組成的一個對象,把他轉成字符串,當做策略的條件,這樣是不是就看起來更加方便了?但其實是有坑的,比如下面這兩種條件,其實就是同一個條件,但是因為序列化時會有順序的問題,導致了兩個相同的條件匹配不到同一個函數:
所以我們需要對條件對象進行排序,要保證這兩個條件匹配到同一個函數,怎么做呢?我們要讓他們順序保持一直就行了!!需要利用到 Map 這個數據結構,Map 的 key 是有順序的~
這樣就保證了不同順序的條件對象,能匹配到同一個函數了~
上面的代碼都是比較散的代碼,如果想要代碼更好的復用,肯定是需要進行封裝,使用一個 class 去封裝,并且你要考慮一些邊界情況,比如:
想要更好地去完成這個方案,我們可以借助另一種設計模式發布訂閱模式,具體代碼請看下方,我建議大家要多看代碼,多敲,從中領略到它到底有啥好處~
class Strategy { map = new Map(); constructor({ defaultCbs, errorCbs }) { // 默認 this.map.set("default", defaultCbs ?? []); // 錯誤 this.map.set("error", errorCbs ?? []); } // 獲取條件key getCondition(condition) { const conditionMap = new Map(); Object.keys(condition) .sort() .forEach((key) => { conditionMap.set(key, condition[key]); }); return JSON.stringify(Object.fromEntries(conditionMap)); } // 增加條件情況 add(condition, conditionCbs) { const currentCondition = this.getCondition(condition); let cbs = this.map.get(currentCondition); if (!cbs) { this.map.set(currentCondition, []); cbs = this.map.get(currentCondition); } cbs.push(...conditionCbs); } // 執行條件情況 do(condition) { const currentCondition = this.getCondition(condition); try { const cbs = this.map.get(currentCondition); if (cbs) { cbs.forEach((cb) => cb(JSON.parse(currentCondition))); } else { // 匹配不到則執行默認函數 const defaultCbs = this.map.get("default"); defaultCbs.forEach((cb) => cb(JSON.parse(currentCondition))); } } catch (e) { // 報錯執行報錯函數 const errorCbs = this.map.get("error"); errorCbs.forEach((cb) => cb(e)); } }}const strategy = new Strategy({ defaultCbs: [ (v) => { console.log("這是默認情況", v); }, ], errorCbs: [ (e) => { console.log("這是錯誤情況", e); }, ],});const condition = { name: "sunshine_lin", weight: 160,};// 此時還沒有注冊條件事件,所以輸出默認事件strategy.do(condition); // 添加條件函數strategy.add(condition, [ (v) => { console.log("事件1", v); }, (v) => { console.log("事件2", v); },]);// 此時有條件事件了,輸入:事件1 事件2strategy.do(condition);const condition2 = { name: "error_lin", weight: 1000000,};// 可以增加報錯條件strategy.add(condition2, [ (v) => { throw new Error("我超重啦!!!!"); },]);// 報錯,輸出:我超重啦!!!!strategy.do(condition2)
本文鏈接:http://www.www897cc.com/showinfo-26-66194-0.html同事的【策略模式】比我高級這么多?我哪里比不過人家?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Python中zoneinfo模塊的用法
下一篇: C++內存管理的奧秘:從基礎到高級