关于javascript:策略模式

36次阅读

共计 4678 个字符,预计需要花费 12 分钟才能阅读完成。

定义一系列的算法,把它们一个个封装起来,并且使它们能够互相替换。


一个基于策略模式的程序至多由两局部组成。第一个局部是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个局部是环境类 Context,Context 承受客户的申请,随后把申请委托给某一个策略类

// 计算员工的年终奖金

// S 奖金
let performanceS = function () {};
performanceS.prototype.caculate = function (salary) {return salary * 4;};
// B 奖金
let performanceB = function () {};
performanceB.prototype.caculate = function (salary) {return salary * 2;};

let Bonus = function () {
    this.salary = null; // 根底薪资
    this.strategy = null; // 对应的策略办法
};
Bonus.prototype.setSalary = function (salary) {this.salary = salary;};

Bonus.prototype.setStrategy = function (strategy) {this.strategy = strategy;};

Bonus.prototype.getBonus = function () {return this.strategy.caculate(this.salary);
};

let bonus = new Bonus();
bonus.setSalary(1000);
bonus.setStrategy(new performanceS());
console.log(bonus.getBonus());

bonus.setStrategy(new performanceB());
console.log(bonus.getBonus());

JavaScript 中应用策略

let strategies = {S: function (salary) {return salary * 4;},
    B: function (salray) {return salray * 2;},
};

var calculateBons = function (key, salary) {return strategies[key](salary);
};

console.log(calculateBons('S', 1000));
console.log(calculateBons('B', 1000));

策略模式对表单的校验

常应用的表单校验

<html>
    <body>
        <form action="http:// xxx.com/register" id="registerForm" method="post">
            请输出用户名:<input type="text" name="userName" /> 请输出明码:<input type="text" name="password" />
            请输出手机号码:<input type="text" name="phoneNumber" />
            <button> 提交 </button>
        </form>
        <script>
            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;
                }
            };
        </script>
    </body>
</html>

应用策略模式

  1. 重构表单的校验
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;}
    },
};
  1. 筹备实现 Validator 类

    Validator 类在这里作为 Context,负责接管用户的申请并委托给 strategy 对象。在给出 Validator 类的代码之前,有必要提前理解用户是如何向 Validator 类发送申请的,这有助于咱们晓得如何去编写 Validator 类的代码。

var validataFunc = function () {var validator = new Validator(); // 创立一个 validator 对象
    /*************** 增加一些校验规定 ****************/
    validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
    validator.add(registerForm.password, 'minLength:6', '明码长度不能少于 6 位');
    validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格局不正确');
    var errorMsg = validator.start(); // 启动校验取得校验后果
    return errorMsg; // 返回校验后果
};
var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function () {var errorMsg = validataFunc(); // 如 果 errorMsg 有确切的返回值,阐明未通过校验
    if (errorMsg) {alert(errorMsg);
        return false; // 阻止表单提交
    }
};

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.shift(); // 用户筛选的 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;
        }
    }
};
  1. 一个文本有多种校验规定

    // 须要校验
    validator.add(registerForm.userName, [
     {
         strategy: 'isNonEmpty',
         errorMsg: '用户名不能为空',
     },
     {
         strategy: 'minLength:6',
         errorMsg: '用户名长度不能小于 10 位',
     },
    ]);
    // 对 add 代码批改
    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 strategies[strategy].apply(dom, strategyAry);
             });
         })(rule);
     }
    };
    Validator.prototype.start = function () {for (var i = 0, validatorFunc; (validatorFunc = this.cache[i++]); ) {var errorMsg = validatorFunc();
         if (errorMsg) {return errorMsg;}
     }
    };
    
    // 业务逻辑中的应用 校验的时候的调用
    var registerForm = document.getElementById('registerForm');
    var validataFunc = function () {var validator = new Validator();
     validator.add(registerForm.userName, [
         {
             strategy: 'isNonEmpty',
             errorMsg: '用户名不能为空',
         },
         {
             strategy: 'minLength:6',
             errorMsg: '用户名长度不能小于 10 位',
         },
     ]);
     validator.add(registerForm.password, [
         {
             strategy: 'minLength:6',
             errorMsg: '明码长度不能小于 6 位',
         },
     ]);
     validator.add(registerForm.phoneNumber, [
         {
             strategy: 'isMobile',
             errorMsg: '手机号码格局不正确',
         },
     ]);
     var errorMsg = validator.start();
     return errorMsg;
    };
    registerForm.onsubmit = function () {var errorMsg = validataFunc();
     if (errorMsg) {alert(errorMsg);
         return false;
     }
    };

总结

  • 策略模式利用组合、委托和多态等技术和思维,能够无效地防止多重条件抉择语句。
  • 策略模式提供了对凋谢—关闭准则的完满反对,将算法封装在独立的 strategy 中,使得它
    们易于切换,易于了解,易于扩大。
  • 策略模式中的算法也能够复用在零碎的其余中央,从而防止许多反复的复制粘贴工作。
  • 在策略模式中利用组合和委托来让 Context 领有执行算法的能力,这也是继承的一种更轻
    便的代替计划。

参考:JavaScript 设计模式与实际

正文完
 0