策略模式
大约 2 分钟约 738 字
定义
策略模式(Strategy Pattern)指的是定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。⽬的就是将策略的实现和使用分离。
策略模式中主要有下面概念:
- Context :封装上下文,根据需要调用需要的策略,屏蔽外界对策略的直接调用,只对外提供一个接口,根据需要调用对应的策略
- Strategy :策略,含有具体的算法,其方法的外观相同,因此可以互相代替
- StrategyMap :所有策略的合集,供封装上下文调用

使用场景
- 多个算法只在行为上稍有不同的场景,这时可以使用策略模式来动态选择算法;
- 算法需要自由切换的场景;
- 有时需要多重条件判断,那么可以使用策略模式来规避多重条件判断的情况;
策略模式可以⽤来封装⼀系列的“业务规则”,只要这些业务规则指向的⽬标⼀致,并且可以被替换使⽤,我们就可以⽤策略模式来封装它们。
优缺点
优点
- 策略之间相互独立,但策略可以自由切换,这个策略模式的特点给策略模式带来很多灵活性,也提高了策略的复用率;
- 如果不采用策略模式,那么在选策略时一般会采用多重的条件判断,采用策略模式可以避免多重条件判断,增加可维护性;
- 可扩展性好,策略可以很方便的进行扩展;
缺点
- 策略相互独立,因此一些复杂的算法逻辑无法共享,造成一些资源浪费;
- 如果用户想采用什么策略,必须了解策略的实现,因此所有策略都需向外暴露,这是违背迪米特法则/最少知识原则的,也增加了用户对策略对象的使用成本。
实现
let strategry = {
A: (salary) => {
return salary * 4
},
B: (salary) => {
return salary * 3
},
C: (salary) => {
return salary * 2
},
}
function calBonus(level, salary) {
return strategry[level](salary)
}
console.log(calBonus('A', 10000))
console.log(calBonus('C', 8000))
// 定义表单验证策略对象
const strategies = {
isNonEmpty(value, errorMsg) {
if (value === '') {
return errorMsg;
}
},
isEmail(value, errorMsg) {
const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$/;
if (!emailReg.test(value)) {
return errorMsg;
}
},
minLength(value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
};
// 表单验证类
class Validator {
constructor() {
this.rules = [];
}
addRule(value, rule, errorMsg) {
this.rules.push(() => strategies[rule](value, errorMsg));
}
validate() {
for (let rule of this.rules) {
const errorMsg = rule();
if (errorMsg) {
return errorMsg;
}
}
}
}
// 使用策略模式进行表单验证
const validator = new Validator();
validator.addRule('example@example.com', 'isNonEmpty', '邮箱不能为空');
validator.addRule('example@example.com', 'isEmail', '请输入有效的邮箱地址');
const error = validator.validate();
if (error) {
console.log(error);
} else {
console.log('表单验证通过');
}