定义一系列的算法,把它们一个个封装起来,并且使它们能够互相替换。
一个基于策略模式的程序至多由两局部组成。第一个局部是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个局部是环境类 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>
应用策略模式
- 重构表单的校验
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 类
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; } }};
一个文本有多种校验规定
// 须要校验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设计模式与实际