行為型模式之策略模式

RobinsonZhang發表於2018-12-06

前言

在講解策略模式之前,我們瞭解下行為型設計模式。那麼行為型是什麼意思呢?主要場景是什麼呢?

行為型設計模式主要是用於不同物件之間職責劃分或者演算法抽象,行為型設計模式不僅僅涉及類和物件,還涉及類或者物件之間的交流模式並加以實現。

感謝作者張容銘對本模式的講解,非常透徹清晰,我只是一個搬運工,做好自己的學習實踐,謹記:他山之石,可以攻玉。

策略模式

策略模式是把一系列的演算法封裝起來,讓其可以相互替換,封裝的演算法具有一定的獨立性,不隨客戶端的變化而變化。

場景應用

馬上到聖誕節了,老闆要讓你做一款活動的促銷活動,根據使用者不同等級給與不同的返現。然後你就開始下面這樣寫了

function return30(price){
    
}

function return50(price){
    
}
複製程式碼

然後開始了switch

我相信不少人都會這樣寫,沒什麼問題,能工作,看上去維護性也很好。

但好像你忘掉了什麼,這只是一堆零散的程式碼啊,我還需要做的是: 1 如何把不同的打折返現模式封裝起來 2 如何根據不同情況去使用我想要的,很明顯目前的方式是不行的,因為目前的函式是暴露在全域性的。如果我另外的位置需要還需要寫這麼一堆switch語句。

switch(user.cheaperLevel){
    case return30 :  return30(price);
    break;
    case return60 :  return60(price);
    break;
}
複製程式碼

價格策略物件

const PriceStrategy = function(){
// 內部演算法物件
    const stragtegy = {
       return30:function(price){
        },
       return60:function(price){
        },
    }
// 策略演算法呼叫介面
   return function(cheaperLevel,price){
       return stragtegy[cheaperLevel] && stragtegy[cheaperLevel](price)
   }
}

// 使用方式
let price = PriceStrategy('return30','321.56')
console.log(price)
複製程式碼

小結:這樣實現之後,我們在使用時只要關注如何呼叫而不用關注原來的演算法;而負責演算法的人也可以統籌所有的演算法策略,通過策略的api暴露的方式提供給使用者。

jq延伸擴充

jq中的策略模式使用案例,相信你一定使用jq的animate的動畫函式。

其呼叫過程是這樣的:

$("div").animate({width:300px},1000,'linear')
$("div").animate({width:300px},1000,'swing')
複製程式碼

通過一個關鍵字我們就可以呼叫其內部封裝的30種動畫,而不用關心其內部實現。

追本溯源,我們定位到jq的原始碼:

// line 660-667 https://github.com/jquery/jquery/blob/2.0.0/src/effects.js
jQuery.easing = {
	linear: function( p ) {
		return p;
	},
	swing: function( p ) {
		return 0.5 - Math.cos( p*Math.PI ) / 2;
	}
};
複製程式碼

表單驗證

除了上面的,其實我們工作中複雜常用的表單驗證也可以用這個設計模式輕鬆實現,甚至我們還可以根據自己的需要去為其增加策略。

const inputStrategy = () => {
    const strategy = {
        notNull : (val) => {
            return /\s+/.test(val) ? '請輸入' : '';
        },
        number :(val) => {
            return val.isNaN ? '請輸入數字' :'';
        }
    }
    return {
        check:(type,value)=>{
           return  strategy[type](value) ;
        },
        // 肯定策略不夠用,為它新增一個自定義的策略Api
        addStrategy:(type,fn)=>{
            strategy[type] = fn ;
        }
    }
}

// 演算法呼叫
let inputValue = document.getElmentById('target');
let isVaild = inputStrategy.check('number',inputValue);
複製程式碼

總結

雖然好像說的很明白了,但好像你覺得並沒有和開始的分支語句有什麼區別,那麼我把區別重點說明下。

  • 將演算法單獨維護在策略物件裡,負責演算法的人不用關心具體業務使用;而業務方只要負責呼叫即可;
  • 通過對演算法的封裝實現了對演算法的引用,避免了重複;
  • 策略模式也是分支語句的一種優化技巧,目的也是為了讓其更加可維護。如果你覺得你的分支語句上升不到策略的高度完全可以用switch來解決這個問題。

相關文章