JS-策略模式

介紹

 定義一系列的算法,把它們一個個封裝起來,將不變的部分和變化的部分隔開,實際就是將算法的使用和實現分離出來;

策略模式由兩部分構成:一部分是封裝不同策略的策略組,另一部分是 Context。通過組合和委託來讓 Context 擁有執行策略的能力,從而實現可複用、可擴展和可維護,並且避免大量複製粘貼的工作。

 

優點

1. 策略模式利用組合,委託等技術和思想,有效的避免很多if條件語句。

2. 策略模式提供了開放-封閉原則,使代碼更容易理解和擴展。

3. 策略模式中的代碼可以複用。

實現

老規矩舉個栗子來解釋一下:公司的年終獎是根據員工的工資和績效來考覈的,績效爲A的人,年終獎爲工資的4倍,績效爲B的人,年終獎爲工資的3倍,績效爲C的人,年終獎爲工資的2倍;

// 方案一:普通寫法
var calculateBouns = function(salary,level) {
    if(level === 'A') {
        return salary * 4;
    }
    if(level === 'B') {
        return salary * 3;
    }
    if(level === 'C') {
        return salary * 2;
    }
};
// 調用如下:
console.log(calculateBouns(4000,'A')); // 16000
console.log(calculateBouns(2500,'B')); // 7500


// 方案二:策略模式
var obj = {
        "A": function(salary) {
            return salary * 4;
        },
        "B" : function(salary) {
            return salary * 3;
        },
        "C" : function(salary) {
            return salary * 2;
        } 
};
var calculateBouns =function(level,salary) {
    return obj[level](salary);
};
console.log(calculateBouns('A',10000)); // 40000

具體分析一下兩種寫法的優劣

方案一:包含了很多if-else語句,函數缺少彈性,如果後面還有DEF等級,又得在函數內部添加判斷,而且算法複用性差

方案二:封裝了基本的業務規則,複用性強

 

表單校驗

表單校驗也是策略模式的一個典型的應用場景,針對於檢驗規則的封裝,普通的表單校驗

一個簡單的登錄表單驗證

<form action = "http://www.baidu.com" id="registerForm" method = "post">
        <p>
            <label>請輸入用戶名:</label>
            <input type="text" name="userName"/>
        </p>
        <p>
            <label>請輸入密碼:</label>
            <input type="text" name="password"/>
        </p>
        <p>
            <label>請輸入手機號碼:</label>
            <input type="text" name="phoneNumber"/>
        </p>
</form>

普通的規則校驗

var registerForm = document.getElementById("registerForm");
registerForm.onsubmit = function(){
    if(registerForm.userName.value === '') {
        alert('用戶名不能爲空');
        return;
    }
    if(registerForm.password.value.length < 6) {
        alert("密碼的長度不能小於6位");
        return;
    }
    if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
        alert("手機號碼格式不正確");
        return;
    }
}

缺點很明顯:

1.函數大,if語句太多;

2.缺乏彈性,規則改變或者新增規則都需要重新修改函數內部,違反了開閉原則

3.複用性差,如果有其他表單也使用類似校驗規則,又得CV大法

下面用策略模式實現

// 策略對象
var strategys = {
    isNotEmpty: function(value,errorMsg) {
        if(value === '') {
            return errorMsg;
        }
    },
    // 限制最小長度
    minLength: function(value,length,errorMsg) {
        if(value.length < length) {
            return errorMsg;
        }
    },
    // 手機號碼格式
    mobileFormat: function(value,errorMsg) {
        if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
            return errorMsg;
        }
    } 
};
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();
                strategyAry.unshift(dom.value);
                strategyAry.push(errorMsg);
                return strategys[strategy].apply(dom,strategyAry);
            });
        })(rule);
    }
};
Validator.prototype.start = function(){
    for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {
    var msg = validatorFunc(); // 開始效驗 並取得效驗後的返回信息
    if(msg) {
        return msg;
    }
    }
};
// 代碼調用
var registerForm = document.getElementById("registerForm");
var validateFunc = function(){
    var validator = new Validator(); // 創建一個Validator對象
    /* 添加一些效驗規則 */
    validator.add(registerForm.userName,[
        {strategy: 'isNotEmpty',errorMsg:'用戶名不能爲空'},
        {strategy: 'minLength:6',errorMsg:'用戶名長度不能小於6位'}
    ]);
    validator.add(registerForm.password,[
        {strategy: 'minLength:6',errorMsg:'密碼長度不能小於6位'},
    ]);
    validator.add(registerForm.phoneNumber,[
        {strategy: 'mobileFormat',errorMsg:'手機號格式不正確'},
    ]);
    var errorMsg = validator.start(); // 獲得效驗結果
    return errorMsg; // 返回效驗結果
};
// 點擊確定提交
registerForm.onsubmit = function(){
    var errorMsg = validateFunc();
    if(errorMsg){
        alert(errorMsg);
        return false;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章