JS设计模式-策略模式 - CNode技术社区

JS设计模式-策略模式
发布于 6 年前 作者 myfirebug 6797 次浏览 来自 分享

定义 定义一系列的算法,把他们一个个封装起来,并且使他们可以互相替换。 优点

    • 策略模式利用组合,委托和多态等技术思想,可以避免多重条件语句。
    • 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的stragety中,使得它们易于切换,理解和扩展。
    • 策略模式中算法也可以在其他地方复用,避免冗余代码。 缺点
  1. 使用策略模式会增加许多策略类或者策略对象。
  2. 要使用stragety,必须要了解所有stragety的细节。此时stragety向客户暴露了其实现,这是有违最少知识原则的。

1.使用策略计算评分内容

假设有如下需求:总评分为5分,评分为1分显示非常差,评分为2显示差,评分为3显示一般,评分为4显示好,评分为5显示非常好。你可能会很自觉写出如下代码:

function getStarText(level) {
 if (level = 1) {
 return '非常差'
 } else if (level = 2) {
 return '差'
 } else if (level = 3) {
 return '一般'
 } else if (level = 4) {
 return '好'
 } else if (level = 5) {
 return '非常好'
 }
}
console.log(getStarText(2)); // 非常差

使用策略实现

let strategies = {
 level1: function (level) {
 return '非常差'
 },
 level2: function (level) {
 return '差'
 },
 level3: function (level) {
 return '一般'
 },
 level4: function (level) {
 return '好'
 },
 level5: function (level) {
 return '非常好'
 }
}
function getStarText(level) {
 return strategies['level' + level] ? strategies['level' + level](level) : '一般'
}
console.log(getStarText(4)); // 非常差

2.使用策略模式实现表单校验 表单验证是一个很常见的功能需求,假设你需要为一个网站编写注册模块。用户需要输入用户、密码、手机号码点击注册 按钮进行注册,在向后端发送请求,需要在前端校验合法法:用户名不能为空,密码不能为空,手机号码不能为空且手机号码必须符合正确的格式。 html代码如下:

<form id="js_register">
 <p>用户名:<input type="text" name="username"></p>
 <p>密 码:<input type="text" name="password"></p>
 <p>手机号码:<input type="text" name="phone"></p>
 <button>提交</button>
</form>

可能我们很容易就写出了以下代码:

var registerForm = document.getElementById('js_register');
registerForm.onsubmit = function() {
 if (registerForm.username.value === '') {
 alert('用户名不能为空');
 return false;
 }
 if (registerForm.password.value === '') {
 alert('密码不能为空');
 return false;
 }
 if (registerForm.phone.value === '') {
 alert('手机号码不能为空');
 return false;
 }
 if (!/^1[3|5|8][0-9]{9}$/.test(registerForm.phone.value)) {
 alert('手机号码格式不正确');
 return false;
 }
}

缺点: 1.registerForm.onsubmit函数比较庞大,包含了很多if-esle语句。 2.registerForm.onsubmit 函数缺乏弹性,如果增加了一种新的校验规则,我们都必须深入registerForm.onsubmit 函数的内部实现,这是违反开放-封闭原则的。 3.算法的复用性差,如果在程序中还有一个登录表单,这个表单也需要进行一些类似的校验,那么我们很可能随处都可见这些校验逻辑规则的复制。 下面,我们使用策略模式来实现表单校验:

// 封装策略对象
let rules = {
 required: function (value, message) {
 if (value === '') {
 return message
 }
 },
 isMobile: function (value, message) {
 if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
 return message
 }
 }
}
// 校验规则
function Validate() {
 this.rules = [];
}
Validate.prototype = {
 constructor: Validate,
 add: function (element, rule) {
 let _self = this;
 for (let i = 0; i < rule.length; i++) {
 (function (rule) {
 let array = rule.type.split(':'),
 error = rule.message;
 _self.rules.push(function () {
 // 取出用户指定的stragety
 let stragety = array.shift();
 // 将input的value放到参数列表最前面
 array.unshift(element.value);
 // 将errMsg放到参数列表最后面
 array.push(error);
 return rules[stragety].apply(element, array);
 })
 })(rule[i]);
 }
 },
 start: function () {
 for (let i = 0; i < this.rules.length; i++) {
 let message = this.rules[i]();
 if (message) {
 return message
 }
 }
 }
}
let registerForm = document.getElementById('js_register'),
 validates = function () {
 let validate = new Validate();
 validate.add(registerForm.username, [
 {type: 'required', message: '用户名不能为空'}
 ]);
 validate.add(registerForm.password, [
 {type: 'required', message: '密码不能为空'}
 ]);
 validate.add(registerForm.phone, [
 {type: 'required', message: '手机号码不能为空'},
 {type: 'isMobile', message: '手机号码格式不正确'}
 ]);
 let message = validate.start();
 return message
 };
validates();
registerForm.onsubmit = function () {
 let message = validates();
 if (message) {
 alert(message);
 return false
 }
}
1 回复

状态模式和策略模式有点相似,有没有想过具体区别。提个小意见,文章尽可能代码为辅,因为看大篇幅代码是个很累的事情。

回到顶部

AltStyle によって変換されたページ (->オリジナル) /