策略模式
策略模式就是将一系列算法封装起来,并使它们相互之间可以替换。被封装起来的算法具有独立性,外部不可改变其特性。简单理解就是把 if 分支用函数封装成一个个代码块,对方法进行抽象,便于后续代码的维护,体高代码复用率,较少代码冗余,缺点就是对于其他没有参与封装的其他开发者来说,他们并不知道有哪些方法可以使用,如果不去阅读这些算法,很容易走回以前的老套路或者重复封装,缺点就是不够直观易懂
对于前端来说策略模式实现的两个步骤
- 实现抽象的方法
把 if else 不用分支处理的事情抽象成一个个不同、独立方法
- 实现对外的接口
提供给外部调用的一个接口,根据外部给的不同的条件,进行不同的逻辑处理,找到对应的抽象的方法
表单验证例子
开发一个用户注册页面,其中表单包含了用户名、密码、确认密码以及手机号码,要求所有数据都不为空,密码至少6位,确认密码必须与密码相等。
准备工作,先把html和css写好
<style>
.flex {
display: flex;
justify-content: space-between;
width: 300px;
margin: 10px;
}
</style>
<form action="" id="form">
<div class="flex">姓名:<input type="text" id="username" /></div>
<div class="flex">密码:<input type="password" id="password1" /></div>
<div class="flex">确认密码:<input type="password" id="password2" /></div>
<div class="flex">手机号:<input type="text" id="phone" /></div>
<div class="flex"><input type="submit" value="提交" /></div>
</form>
直接做表单验证:
var formData = document.getElementById('form')
formData.onsubmit = function () {
var name = this.username.value
var pwd1 = this.password1.value
var pwd2 = this.password2.value
var tel = this.phone.value
if (name.replace(/(^\s*)|(\s*$)/g, '') === '') {
alert('用户名不能为空')
return false
}
if (pwd1.replace(/(^\s*)|(\s*$)/g, '') === '') {
alert('密码不能为空')
return false
}
if (pwd2.replace(/(^\s*)|(\s*$)/g, '') === '') {
alert('确认密码不能为空')
return false
}
if (pwd2 !== pwd1) {
alert('确认密码与原密码不相同!')
return false
}
if (tel.replace(/(^\s*)|(\s*$)/g, '') === '') {
alert('手机号码不能为空')
return false
}
if (!/^1[3,4,5,7,8,9][0-9]\d{8}$/.test(tel)) {
alert('手机号码格式不正确')
return false
}
alert('注册成功')
}
直接做表单验证整个逻辑对于新手来说会很直观,没那么多弯弯绕绕的,但是缺点也明显,4个表单数据,就用了6个if去判断,如果这个页面不是用户注册,而是某个管理页面中的表单,包含了十多个表单数据呢,那只会更多。需要验证的越多,代码就会越来越臃肿,当需要进行很多验证的时候,可以考虑策略模式
第一步,把 if else 不用分支处理的事情抽象成一个个不同、独立方法
function Validate() {}
// 定义在原型链,方便调用
Validate.prototype.rules = {
// 是否手机号
isMobile: function (str) {
var rule = /^1[3,4,5,7,8,9][0-9]\d{8}$/
return rule.test(str)
},
// 是否必填
isRequired: function (str) {
// 除去首尾空格
var value = str.replace(/(^\s*)|(\s*$)/g, '')
return value !== ''
},
// 最小长度
minLength: function (str, length) {
var strLength = str.length
return strLength >= length
},
// 是否相等
isEqual: function () {
// 可以接收多个参数比较
var args = Array.prototype.slice.call(arguments)
// 取首项与后面所有的项比较,如果每个都相等,就返回true
var equal = args.every(function (value) {
return value === args[0]
})
return equal
}
}
第二步,实现一个对外暴露的接口,或者说方法,供外部调用
Validate.prototype.test = function (rules) {
var v = this
var valid // 保存校验结果
for (var key in rules) {
// 遍历校验规则对象
for (var i = 0; i < rules[key].length; i++) {
// 遍历每一个字段的校验规则
var ruleName = rules[key][i].rule // 获取每一个校验规则的规则名
var value = rules[key][i].value // 获取每一个校验规则的校验值
if (!Array.isArray(value)) {
// 统一校验值为数组类型
value = new Array(value)
}
var result = v.rules[ruleName].apply(this, value) // 调用校验规则方法进行校验
if (!result) {
// 如果校验不通过,就获取校验结果信息,并立即跳出循环不再执行,节约消耗
valid = {
errValue: key,
errMsg: rules[key][i].message
}
break
}
}
if (valid) {
// 如果有了校验结果,代表存在不通过的字段,则立即停止循环,节约消耗
break
}
}
return valid // 把校验结果返回出去
}
这个时候外部环境就可以调用了,外部环境要知道调用的格式,就是说要知道怎么用
var formData = document.getElementById('form')
formData.onsubmit = function () {
event.preventDefault() //阻止元素默认行为
console.log(this.username.value)
var validator = new Validate()
var result = validator.test({
username: [
{
rule: 'isRequired',
value: this.username.value,
message: '用户名不能为空!'
}
],
password1: [
{
rule: 'isRequired',
value: this.password1.value,
message: '密码不能为空!'
},
{
rule: 'minLength',
value: [this.password1.value, 6],
message: '密码长度不能小于6个字符!'
}
],
password2: [
{
rule: 'isRequired',
value: this.password2.value,
message: '确认密码不能为空!'
},
{
rule: 'minLength',
value: [this.password2.value, 6],
message: '确认密码长度不能小于6个字符!'
},
{
rule: 'isEqual',
value: [this.password2.value, this.password1.value],
message: '确认密码与原密码不相同!'
}
],
isMobile: [
{
rule: 'isRequired',
value: this.phone.value,
message: '手机号不能为空!'
},
{ rule: 'isMobile', value: this.phone.value, message: '手机号格式不正确!' }
]
})
if (result) {
console.log(result)
} else {
console.log('校验通过')
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。