策略模式

策略模式

@(记录)[读书笔记]

策略模式:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。

将不变的部分和变化的部分隔开是每一个设计模式的主题,策略模式的目的是将算法的使用与算法的实现分离开来。
一个基于策略模式的程序化至少有两部分组成,一组策略类,封装了具体的算法并负责具体的计算过程;另一组是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var performanceS = function() {};
performanceS.prototype.calculate = function(salary) {
return salary * 4;
}
var performanceA = function() {};
performanceA.prototype.calculate = function(salary) {
return salary * 3;
}
var performanceB = function() {};
performanceB.prototype.calculate = function(salary) {
return salary * 2;
}
var 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.calculate(this.salary);
}
var bonus = new Bonus();
bonus.setSalary(10000);//设置salary
bonus.setStrategy(new performanceS());//设置strategy策略
console.log(bonus.getBonus());//40000
bonus.setStrategy(new performanceA());//设置strategy策略
console.log(bonus.getBonus());//30000

关于策略模式的定义,其实就是定义一系列的算法,把他们封装成策略类,算法被封装在策略内部的方法里,在客户对Context发起请求时,Context总是把请求委托给策略对象中间的某个进行计算。

以上策略模式的JavaScript版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var strategies = {
"S": function(salary) {
return salary * 4;
},
"A": function(salary) {
return salary * 3;
},
"B": function(salary) {
return salary * 2;
}
};
var calculateBonus = function(level, salary) {
return strategies[level](salary);
};
console.log(calculateBonus('S', 20000));//80000
console.log(calculateBonus('A', 10000));//30000

可以定义动画的模式,不同动画或者速度定义不同的策略进行调用;
可以定义表单登录窗口的验证策略,用户名,密码,电子邮箱等不同的验证有不同的策略;

使用策略模式编写表单验证:

1
2
3
4
5
6
<form action=".../register" id="registerForm" method="post">
请输入用户名:<input type="text" name="userName">
请输入密码:<input type="password" name="password">
请输入手机号码:<input type="text" name="phoneNumber">
<button>提交</button>
</form>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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)) {//正则验证,1开头接着(3 or 5 or 8),最后9个数字结尾
return errorMsg;
}
}
};
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, validataFunc; validataFunc = this.cache[i++];) {
var msg = validataFunc();//开始验证,并取得验证后的返回信息
if (msg) {//如果有确切的返回值,说明验证没有通过
return msg;
}
}
};
var registerForm = document.getElementById('registerForm');
//Context,负责接收用户请求并委托给strategy对象
var validataFunc = function() {
var validator = new Validator();
//添加一些验证规则
validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
validator.add(registerForm.password, 'minLength:6', '密码长度不能少于6位');
validator.add(registerForm.phoneNumber, 'isMobile', '用户名不能为空');
var errorMsg = validator.start();//获取验证结果
return errorMsg;//返回验证结果
}
registerForm.onsubmit = function() {
var errorMsg = validataFunc();//如果errorMsg有确切的返回值,说明未通过验证
if (errorMsg) {
alert(errorMsg);
return false;//阻止表单提交,阻止默认行为
};
}

检测

如果想要一个表单验证多个规则:
改变Validator.prototype.add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
};

坚持原创技术分享,您的支持将鼓励我继续创作!