策略模式定义:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。
一个策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类。要做到这点,说明Context中要维持对某个策略对象的引用。
从第一上看,策略模式就是用来封装算法的。但实际开发中,我们通常会把算法含义扩散开来,使用策略模式封装一些列业务规则。
回到主题,编写一个用策略模式来校验用户是否输入合法数据的例子:
FORM表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<form action="http://xxx.com/register" id="registerForm" method="post">
请输入用户名:<input name="userName" />
请输入密码:<input name="password" />
请输入手机号:<input name="phoneNumber" />
<button>提交</button>
</form>
</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 类:
var Validator = function() {
this.cache = []
}
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:10',
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) {
return alert(errorMsg)
}
}
使用策略模式重构代码之后,我们仅仅通过“配置”的方式就可以完成一个表单的校验,这些校验规则也可以复用在程序任何地方,或者作为插件的形式,方便地移植到其他项目中。