将定义的一组算法封装起来,使其相互之间可以替换,封装的算法具有一定独立性,不会随客户端变化而变化(避免大量的 if else 或 swith case);
适用场景:
- 行为切换:系统有很多类,这些类的区别仅仅在于它们的 行为不同;使用策略模式,可以 动态地 让 用户对象 在这些行为中选择一个行为;
- 算法选择:系统中需要 动态地 在 几种算法(算法 就是 策略)中 选择一种;
优点:
- 开闭原则:策略模式 提供了对 开闭原则 的支持,可以在不修改原有系统的基础上,选择不同的行为,也可以 额外扩展其它行为;
- 避免代码冗余:可以 避免使用多重条件判定语句;可以避免出现大量的 if … else … 语句,switch 语句等;
- 安全保密:策略模式可以 提高算法的 保密性 和 安全性; 在终端使用策略时,只需要知道策略的作用即可,不需要知道策略时如何实现的;
缺点:
- 策略类选择:客户端 必须 知道所有的 策略类,并且自行决定 使用哪个策略类;
- 增加复杂性:如果系统很复杂,会 产生很多策略类;
类图
bad
class Customer {
constructor(type) {
this.type = type;
}
pay(amount) {
if (this.type == '会员顾客') {
return amount * .9;
} else if (this.type == 'VIP顾客') {
return amount * .8;
}
return amount;
}
}
let c1 = new Customer('普通顾客');
console.log(c1.pay(100)); // 100
let c2 = new Customer('会员顾客');
console.log(c2.pay(100)); // 90
let c3 = new Customer('VIP顾客');
console.log(c3.pay(100)); // 80
good
class Customer {
constructor(kind) {
this.kind = kind;
}
cost(amount) {
return this.kind.discount(amount);
}
}
class Normal {
discount(amount) {
return amount;
}
}
class Member {
discount(amount) {
return amount * .9;
}
}
class VIP {
discount(amount) {
return amount * .8;
}
}
let c1 = new Customer(new Normal());
console.log(c1.cost(100));
c1.kind = new Member();
console.log(c1.cost(100));
c1.kind = new VIP();
console.log(c1.cost(100));
better
class Customer {
constructor() {
// 把算法封装在策略对象中,指定算法调用即可
this.kinds = {
normal: function (price) {
return price;
},
member: function (price) {
return price * .9;
},
vip: function (price) {
return price * .8;
}
}
}
cost(kind, amount) {
return this.kinds[kind](amount);
}
}
let c = new Customer();
console.log(c.cost('normal', 100));
console.log(c.cost('member', 100));
console.log(c.cost('vip', 100));
应用场景
表单校验
<!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 id="userform">
用户名 <input type="text" name="username" />
密码 <input type="text" name="password" />
手机号 <input type="text" name="mobile" />
<input type="submit">
</form>
<script>
let Validator = (function () {
let rules = {
notEmpty(val, msg) {
if (val == '') {
return msg;
}
},
minLength(val, length, msg) {
if (val == '' || val.length < length) {
return msg;
}
},
maxLength(val, length, msg) {
if (val == '' || val.length > length) {
return msg;
}
},
isMobile(val, msg) {
if (!/^1\d{10}/.test(val)) {
return msg;
}
}
}
let checks = [];
function add(element, rule) {
checks.push(function () {
let fnName = rule.shift();
return rules[fnName] && rules[fnName].apply(element, [element.value, rule]);
});
}
function start() {
for (let i = 0; i < checks.length; i++) {
let msg = checks[i]();
if (msg) {
return msg;
}
}
}
return {
add,
start,
}
})();
let form = document.getElementById('userform');
form.onsubmit = function () {
Validator.add(form.username, ['notEmpty', '用户名不能为空']);
Validator.add(form.password, ['minLength', 6, '密码小于 6 位最少长度']);
Validator.add(form.password, ['maxLength', 8, '密码大于 8 位最大长度']);
Validator.add(form.mobile, ['isMobile', '手机号不合法']);
let msg = Validator.start();
if (msg) {
alert(msg);
return false;
}
alert('校验通过');
return true;
}
</script>
</body>
</html>
状态模式
上一篇