在生活中,我们去某个地方,可以走路,骑自行车,坐地铁,坐火箭等等,方案很多。
策略模式的定义:定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换。
1,计算奖金
1.1,根据员工绩效和工资来发奖金。
//策略模式:最初代码实现
var calculateBonus = function (level, salary) {
if (level === 'S') {
return salary * 5
}
if (level === 'A') {
return salary * 3
}
if (level === 'B') {
return salary * 2
}
}
console.log(calculateBonus('S', 4000))
console.log(calculateBonus('B', 2000))
缺点:
calculateBonus 里全是if-else,所有的逻辑都在这里面实现;
calculateBonus缺乏弹性,如果新增一个等级C,那么就不得不修改calculateBonus的代码
复用性差
1.2,javaScript版策略模式
// js版本的策略模式->1.html
var strategies = {
'S': function (salary) {
return salary * 5
},
'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', 4000))
console.log(calculateBonus('B', 2000))
2,表单校验
2.1,实现一个普通的表单校验功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://test.com/register" method='post' id="registerForm">
请输入用户名:<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>
缺点很明显:
所有的逻辑都在registerForm.onsubmit中,包含很多if-else语句
registerForm.onsubmit缺乏弹性
算法复用性差
2.2,策略模式重构表单校验
(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
}
},
}
(2)接下来我们来实现Validator类。Validator类在这里作为Context,负责接收用户的请求并委托给strategy对象。先看一下Validator类对象是如何工作的,这样便于我们编写Validator类的代码:
//新增方法,统一管理form
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
}
var registerForm = document.getElementById('registerForm')
registerForm.onsubmit = function () {
var errorMsg = validataFunc()
if (errorMsg) {
alert(errorMsg)
return false
}
}
(3)可以看到,validator对象时通过add方法添加校验规则,add方法有三个参数:
- registerForm.passWord:指参与校验的input框
- 'minLength:6':以冒号隔开的字符串。冒号前面的minLength是校验的策略名,6是需要的参数
- '密码长度不能小于6位':校验未通过时的错误信息
最后还需要一个start方法,用来对add进来的内容进行校验,并返回错误信息。如果返回了错误信息,registerForm.onsubmit()方法返回false来阻止表单提交。
// Validator类在这里作为Context,负责接收用户的请求并发送给strategies
var Validator = function () {
this.cache = []
}
// add中保存需要处理的函数
Validator.prototype.add = function (dom, rule, errorMsg) {
this.cache.push(function () {
var array = rule.split(':')
var strategy = array.shift()
array.unshift(dom.value)
array.push(errorMsg)
return strategies[strategy].apply(dom, array)
})
}
Validator.prototype.start = function () {
for (var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
var errorMsg = validatorFunc()
if (errorMsg) {
return errorMsg
}
}
}
2.3,一个文本框可对应多个校验规则
实际上2.2可以实现这个功能,只是不太好看
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://test.com/register" method='post' id="registerForm">
请输入用户名:<input type="text" name="userName" />
请输入密码:<input type="text" name="passWord" />
请输入手机号:<input type="text" name="phoneNumber" />
<button>提交</button>
</form>
<script>
// 这里主要是为了在一个输入框中匹配多个验证规则;实际上之前的策略可以实现,多写几次就好了
/* 策略对象 */
var strategies = {
isNonEmpty: function (value, errorMsg) {
if (value === '') {
console.log(errorMsg)
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 = []
}
// add中保存需要处理的函数
Validator.prototype.add = function (dom, rules) {
var self = this
for (let i = 0, rule; rule = rules[i]; i++) {
(function (rule) {
self.cache.push(function () {
var startegyArr = rule.startegy.split(':')
var startegy = startegyArr.shift()
startegyArr.unshift(dom.value)
startegyArr.push(rule.errorMsg)
return strategies[startegy].apply(dom, startegyArr)
})
})(rule)
}
}
// 上面写法可以改写成这个
// Validator.prototype.add = function (dom, rules) {
// var self = this
// for (let i = 0; i < rules.length; i++) {
// self.cache.push(function () {
// var rule = rules[i]
// var startegyArr = rule.startegy.split(':')
// var startegy = startegyArr.shift()
// startegyArr.unshift(dom.value)
// startegyArr.push(rule.errorMsg)
// return strategies[startegy].apply(dom, startegyArr)
// })
// }
// }
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, [{
startegy: 'isNonEmpty',
errorMsg: '用户名不能为空',
}, {
startegy: 'minLength:3',
errorMsg: '密码长度不能小于3位',
}])
validator.add(registerForm.passWord, [{
startegy: 'minLength:6',
errorMsg: '密码长度不能小于6位',
}])
validator.add(registerForm.phoneNumber, [{
startegy: 'isMobile',
errorMsg: '手机号码格式不正确',
}])
var errorMsg = validator.start()
return errorMsg
}
registerForm.onsubmit = function () {
var errorMsg = validataFunc()
if (errorMsg) {
alert(errorMsg)
return false
}
}
</script>
</body>
</html>
3,策略模式的优缺点
优点:
- 策略模式利用组合、委托、多态等技术和思想,可以有效地避免多重条件选择语句
- 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,使得他们易于切换,易于理解,易于扩展
- 复用性强
缺点: - 用户在使用策略模式时,需要了解其中所有的细节,strategy要暴露所有实现,违反最少知识原则
网友评论