設計模式之策略模式

@(前端)[設計模式,JavaScript,TypeScript]javascript

策略模式解決的問題:策略模式要解決的問題是,代碼的複用和擴展問題。若是沒有策略模式的代碼是將處理函數代碼與邏輯代碼混在一塊兒寫,這樣寫的好處是一次寫好,但代碼的擴展性與代碼的複用性很差。html

沒有用策略模式的例子代碼前端

var calculateBonus = function( performanceLevel, salary ){
    if ( performanceLevel === 'S' ){ 
        return salary * 4;
    }
    if ( performanceLevel === 'A' ){
        return salary * 3;
    }
    if ( performanceLevel === 'B' ){
        return salary * 2;
    } 
};
calculateBonus( 'B', 20000 ); //40000 
calculateBonus( 'S', 6000 ); //    24000

能夠看到的缺點是:若是想要擴充代碼,只能在原來的對象上插入新的代碼,對於代碼的原做者來講這不是爲題,可是對於看別人寫的代碼的人來講這樣的代碼想要作後期的維護難度之高可想而知。爲了寫出具備高複用性,好維護的,可擴展的代碼來講這樣的代碼風格是不合適的。java

解決問題的思路

1.分離出代碼中「變」與「不變」的部分。其中「變」的部分是啥?應該是後續代碼中要擴展的部分,不是將內容固定死的代碼。而不變的部分就是代碼調用部分,一般來講代碼中的調用部分是固定不變的。
2.因此將原本深度耦合的代碼分離出來,我本身給取了名字叫條件代碼調用代碼;條件代碼時可變的可擴展的,一般放到外部的模塊中用來調用和提升可維護性。而調用代碼提供set`get類方法用來設置條件代碼的運行時須要的參數和調用調用代碼用來輸出結果。typescript

條件代碼

/* 定義各類計算方式 */
class L1{
    calculate(base:number){
        return base*2;
    }
}
class L2{
    calculate(base:number){
        return base*3;
    }
}
class L3 {
    calculate(base: number) {
        return base * 4;
    }
}

調用代碼

/* 定義計算的調用方法類 */
 class Calculate{
    private base: number;
    private way: any;
    setBase(base: number) {
        this.base = base;
    }
    setLeve(leve:Object) {
        this.way = leve;
    }
    getResult(){
        return this.way.calculate(this.base);
    }
}

業務代碼(用來輸出結果的代碼)

let calculater = new Calculate();  //實例化生成可調用對象
calculater.setBase(1000); //設置計算基礎
calculater.setLeve( new L1() ); //設置計算的方式
console.log(calculater.getResult()); //get類方法,輸出最後的結果

小結

從以上代碼可看出,擴展可在條件代碼中擴展。保持了代碼的高擴展和高可維護性。設計模式

一個很好的決策模式的代碼

html代碼app

<body>
    <form action="#" method="post">
        <span>用戶名:</span><input type="text" name="user">
        <span>密碼:</span><input type="password" name="pwd">   
        <span>手機號碼:</span><input id="ph" type="text" name="phoneNumber">
        <input type="submit" value="提交">
    </form>
<script src="ms/m3.js"></script>
</body>

typescript代碼dom

/* 定義檢查表單的規則 */
namespace RuleList{
    export const Rules: any = {
        "isNotEmpty": function (value: any, errMsg: string) {
            console.log(11);
            if (value === '') return errMsg;
        },
        "minLength": function (value: any, minLength: number, errMsg: string) {
            console.log(22);
            if (value.length < minLength) return errMsg;
        },
        "isMobile": function (value: any, errMsg: string) {
            console.log(33);
            if (!/^1[3|5|8][0-9]{9}$/.test(value)) return errMsg;
        }
    }
}

/* 定義檢查表單的方法類:add():添加檢查的規則; start():開始檢查 */
class Validator {
    cache: object[] = [];
    add(dom: any, rule: string, errMsg: string) {
        let arr: any = rule.split(':');
        this.cache.push(function () {
            let whichRule: string = arr.shift();
            arr.unshift(dom.value);
            arr.push(errMsg);
            return RuleList.Rules[whichRule].apply(dom, arr);
        });
    };
    start() {
        for (let i: number = 0, func: any; i < this.cache.length; i++) {
            func = this.cache[i];
            let msg = func();
            if (msg) return msg;  //若是有返回值說明驗證沒有經過
        }
    }
}

/* 策略模式的表單校驗 */
let regForm = document.querySelector('form');
let usr:any = document.querySelector('input[type=text]:first-of-type');
let pwd:any = document.querySelector('input[type=password]');
let phone:any = document.querySelector('#ph');

/* 檢查表單的函數 ->1.1 */
let ValidataFunc = function(){
    let validator = new Validator();
    validator.add(usr, 'isNotEmpty','用戶名爲空');
    validator.add(pwd, 'isNotEmpty', '密碼爲空');
    validator.add(pwd, 'minLength:6', '密碼小於6位');
    validator.add(phone,'isMobile','號碼不是手機號碼');
    let msg = validator.start();
    return msg;
}
/* 檢查表單的函數 ->1. */
if( regForm ){
    regForm.onsubmit = function(){
        let errMsg = ValidataFunc();
        if( errMsg ){
            alert(errMsg);
            return false;
        }
    }
}
相關文章
相關標籤/搜索