策略模式
定义
定义一系列的算法,把他们封装成策略类,并使他们可以相互替换.
策略模式的目的就是把算法的使用和实现分离开来.
一个基于策略模式的至少由两部分组成.第一部分是一组策略类(可变),策略类封装了具体的算法,并负责具体的计算过程.第二个部分是环境类Context(不变),Context接受客户的请求,随后将请求委托给某一个策略类,要做到这一点,说明Context中要维持某个某个策略类的引用
基于类的策略模式
// 模拟策略类的接口
class Strategy {
doOperation() {
throw new Error("子类必须实现doOperation方法");
}
}
// 策略类
// 拥有相同的接口doOperation,环境类中可以直接调用
class OperationAdd extends Strategy {
doOperation(num1, num2) {
return num1 + num2;
}
}
class OperationSubstract extends Strategy {
doOperation(num1, num2) {
return num1 - num2;
}
}
class OperationMultiply extends Strategy {
doOperation(num1, num2) {
return num1 * num2;
}
}
// 环境类
// 持有策略类对象的引用
class Context {
constructor(strategy) {
this.strategy = strategy;
}
// 统一调用策略类对象的方法
executeStrategy(num1, num2) {
return this.strategy.doOperation(num1, num2);
}
// 更换策略类对象
setStrategy(strategy) {
this.strategy = strategy;
}
}
const context = new Context(new OperationAdd());
const retAdd = context.executeStrategy(1, 1);
console.log("retAdd:>>>", retAdd); //2
context.setStrategy(new OperationSubstract());
const retSubstract = context.executeStrategy(10, 1);
console.log("retSubstract:>>>", retSubstract); //9
context.setStrategy(new OperationMultiply());
const retMultiply = context.executeStrategy(2, 2);
console.log("retMultiply:>>>", retMultiply); //4
javascript策略模式-表单验证
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>策略模式-校验表单</title>
</head>
<body>
<form id="registerForm" method="post">
用户名: <input type="text" name="username" /><br />
密码:<input type="text" name="password" /><br />
手机号码:<input type="text" name="phone" /><br />
<button type="submit">提交</button>
</form>
<script>
//策略类对象
const strategies = {
isNoEmpty(value, errMsg) {
if (value == "") {
return errMsg;
}
},
isNoSpace(value, errMsg) {
if (value.trim() == "") {
return errMsg;
}
},
minLength(value, length, errMsg) {
if (value.trim().length < length) {
return errMsg;
}
},
maxLength(value, length, errMsg) {
if (value.trim().length > length) {
return errMsg;
}
},
isMobile(value, errMsg) {
if (
!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(
value
)
) {
return errMsg;
}
},
};
// 验证类
class Validator {
constructor() {
// 存储待执行的验证函数
this.caches = [];
}
// 保存验证函数
//dom:待验证的表单项,如input
// rules:{strategy:string,errMsg:string}[]
add(dom, rules) {
let strategyArr, strategyName;
for (let i = 0, rule; (rule = rules[i]); i++) {
strategyArr = rule.strategy.split(":");
strategyName = strategyArr.shift();
strategyArr.unshift(dom.value);
strategyArr.push(rule.errMsg);
this.caches.push(() => {
// 通过不同的策略名字来来调用不同的算法策略
return strategies[strategyName].apply(dom, strategyArr);
});
}
}
start() {
console.log(this.caches.length);
let errMsg;
for (let i = 0, fn; (fn = this.caches[i++]); ) {
errMsg = fn();
if (errMsg) {
return errMsg;
}
}
}
}
const form = document.querySelector("#registerForm");
// 这里有bug,isNOEmpty没有显示
form.onsubmit = function (e) {
try {
const ret = validateFunc();
if (ret) {
console.log(ret);
}
} catch (e) {
console.log(e);
}
e.preventDefault();
return false;
};
function validateFunc() {
const validator = new Validator();
validator.add(form.username, [
{ strategy: "isNoEmpty", errMsg: "用户名不能为空" },//通过strategy指定不同的算法
{ strategy: "minLength:6", errMsg: "用户名至少为6位" },
]);
validator.add(form.password, [
{ strategy: "isNoSpace", errMsg: "密码不能为空" },
{ strategy: "minLength:6", errMsg: "密码至少为6位" },
]);
validator.add(form.phone, [
{ strategy: "isNoSpace", errMsg: "手机号码不能为空" },
{ strategy: "isMobile", errMsg: "手机号码格式不对" },
]);
return validator.start();
}
</script>
</body>
</html>