javascript策略模式

定義

策略模式指的是定義一系 列的算法,把它們一個個封裝起來。將不變的部分和變化的部分隔開是每一個設計模式的主題,策 略模式也不例外,策略模式的目的就是將算法的使用與算法的實現分離開來。html

一個基於策略模式的程序至少由兩部分組成。第一個部分是一組策略類,策略類封裝了具體 的算法,並負責具體的計算過程。 第二個部分是環境類 Context,Context接受客戶的請求,隨後 把請求委託給某一個策略類。要作到這點,說明 Context中要維持對某個策略對象的引用算法

<!--algorithm-->
var strategies = {
    s: function(salary){
        return salary *4;
    },
    a: function(salary){
        return salary * 3;
    },
    b: function(salary){
        return salary * 2
    }
}

<!--context-->
var calculateBonus = function(level, salary){
    return strategies[level](salary)
}

複製代碼

更廣義的「算法

在實際開發中,咱們一般會把算法的含義擴散開來,使策略模式也能夠用來封裝 一系列的「業務規則」。只要這些業務規則指向的目標一致,而且能夠被替換使用,咱們就能夠 用策略模式來封裝它們。設計模式

實戰

背景

在一個 Web項目中,註冊、登陸、修改用戶信息等功能的實現都離不開提交表單。 在將用戶輸入的數據交給後臺以前,經常要作一些客戶端力所能及的校驗工做,好比註冊的 時候須要校驗是否填寫了用戶名,密碼的長度是否符合規定,等等。這樣能夠避免由於提交不合 法數據而帶來的沒必要要網絡開銷。網絡

假設咱們正在編寫一個註冊的頁面,在點擊註冊按鈕以前,有以下幾條校驗邏輯。app

  1. 用戶名不能爲空。
  2. 密碼長度不能少於 6位。
  3. 手機號碼必須符合格式。

表單校驗的第一個版本(傳統版本)

<body>
    <form action="http:// xxx.com/register" id="registerForm" method="post">
    請輸入用戶名:<input type="text" name="userName"/ >
    請輸入密碼:<input type="text" name="password"/ >
</body>
複製代碼
var registerForm = document.getElementById( 'registerForm' );
registerForm.onsubmit = function(){
    if ( registerForm.userName.value === '' ){
        alert ( '用戶名不能爲空' );
        return false;
    }
    if ( registerForm.password.value.length < 6 ){
        alert ( '密碼長度不能少於 6 位' );
        return false;
    }
    if ( !/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value ) ){
        alert ( '手機號碼格式不正確' );
        return false;
    }
}
複製代碼
  1. registerForm.onsubmit 函數比較龐大,包含了不少 if-else 語句,這些語句須要覆蓋全部的校驗規則。
  2. registerForm.onsubmit 函數缺少彈性,若是增長了一種新的校驗規則,或者想把密碼的長
  3. 度校驗從 6改爲 8,咱們都必須深刻 registerForm.onsubmit 函數的內部實現,這是違反開放 — 封閉原則的。
  4. 算法的複用性差,若是在程序中增長了另一個表單,這個表單也須要進行一些相似的校驗,那咱們極可能將這些校驗邏輯複製得漫天遍野。

用策略模式重構表單校驗

下面咱們將用策略模式來重構表單校驗的代碼,很顯然第一步咱們要把這些校驗邏輯都封裝 成策略對象:dom

var strategies = {
    isNonEmpty: function(value, errorMsg){
        if(value === ''){
            return errorMsg;
        }
    },
    minLength: function(value, length, errorMsg){
        if(value.length < length){
            return errorMsg
        }
    },
    isMobile: function(value, errorMsg){
        if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){
            return errorMsg;
        }
    }
}
複製代碼

Validator 類的實現:函數

var Validator = function(){
    this.cache = [];
}

Validator.prototype.add = function(dom, rule, errorMsg){
    var ary = rule.split(':');// 把 strategy 和參數分開
    this.cache.push(function(){// 把校驗的步驟用空函數包裝起來,而且放入 cache
        var strategy = ary.shifg();// 用戶挑選的 strategy
        ary.unshift(dom.value);// 把 input 的 value 添加進參數列表
        ary.push(errorMsg);// 把 errorMsg 添加進參數列表
        return strategies[strategy].apply(dom, ary);
    })
}

Validator.prototype.start = function(){
    for(var i=0, validatorFunc; validatorFunc = this.cache[i++]){
        var msg = validatorFunc();// 開始校驗,並取得校驗後的返回信息
        if(msg){ // 若是有確切的返回值,說明校驗沒有經過
            return msg;
        }
    }
}


複製代碼

使用策略模式重構代碼以後,咱們僅僅經過「配置」的方式就能夠完成一個表單的校驗, 這些校驗規則也能夠複用在程序的任何地方,還能做爲插件的形式,方便地被移植到其餘項 目中。post

在修改某個校驗規則的時候,只須要編寫或者改寫少許的代碼。好比咱們想將用戶名輸入框 的校驗規則改爲用戶名不能少於 4個字符。能夠看到,這時候的修改是絕不費力的。代碼以下:ui

validator.add( registerForm.userName, 'isNonEmpty', '用戶名不能爲空' );

// 改爲:
validator.add( registerForm.userName, 'minLength:10', '用戶名長度不能小於 10 位' );
複製代碼

給某個文本輸入框添加多種校驗規則

<!--Validator類-->
var Validator = function(){
    this.cache = [];
};

Validator.prototype.add = function(dom, rules){
    var self = this;
    for(var i=0, rule; rule = rules[i++]){
        (function(rule){
            var strategyAry = rule.strategy.split(':');
            var errorMsg = rule.errorMsg;
            
            self.cache.push(function(){
                var strategy = strategyAry.shift();
            })
        })(rule)
    }
}

Validator.prototype.start = function(){
    for(var i=0, validatorFunc;validatorFunc = this.cache[i++];){
        var errorMsg = validatorFunc();
        if(errorMsg){
            return errorMsg;
        }
    }
}

複製代碼

策略模式的優缺點

優勢:this

  1. 策略模式利用組合、委託和多態等技術和思想,能夠有效地避免多重條件選擇語句。
  2. 策略模式提供了對開放 — 封閉原則的完美支持,將算法封裝在獨立的 strategy 中,使得它們易於切換,易於理解,易於擴展。
  3. 策略模式中的算法也能夠複用在系統的其餘地方,從而避免許多重複的複製粘貼工做。
  4. 在策略模式中利用組合和委託來讓 Context擁有執行算法的能力,這也是繼承的一種更輕便的替代方案。

缺點:

  1. 使用策略模式會在程序中增長許多策略類或者策略對象
  2. ,要使用策略模式,必須瞭解全部的 strategy ,必須瞭解各個 strategy 之間的不一樣點, 這樣才能選擇一個合適的 strategy 。
相關文章
相關標籤/搜索