1. 策略模式
1.1 定义
策略模式(Strategy):策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,且具有一定的独立性, 不会随客户端的变化而变化.
一系列的算法, 可以相互醍醐, 也就是说为了同一个目的, 可能采取的算法不一样, 同时要体现出独立性.策略模式将这些算法封装成一个一个的类,可以任意的替换
1.2 作用
- 减轻当代码中过多if...else带来的复杂度和难以维护的问题.
- 让一个对象可以动态得在许多行为中选择一种行为.
- 提高代码的可扩展性,让算法可以自由切换.
1.3 应用场景
- 场景一 根据不同的操作类型进行不同的DOM操作
// 操作DOM元素实现动画效果
let box = document.querySelector('.box');
// 根据不同的type进行不同的DOM操作, type 操作的类型, data表示的数值
function run(type,data){
if(type === 'moveY'){
box.style.transform = `translateY(${data}px)`
}else if(type === 'zoom'){
box.style.transform = `scale(${data})`
}else if(type === 'changeColor'){
box.style.backgroundColor = data
}else {
box.style.opacity = data
}
}
box.addEventListener('click' ,ev =>{
run('zoom',2)
})
上面的代码我们通过对run函数传入不同的操作类型和对应的数值, 实现对DOM的操作, 可以看到我们写了非常多的if...else, 看起来非常臃肿, 模块之间耦合性比较强, 可扩展性不强, 当代码的分支判断语句越来越长时,代码非常难以维护, 此时我们可以利用策略模式优化一下代码.
let box = document.querySelector('.box');
let Strategy = (function (){
//利用闭包 保存所有策略和对应操作
let s ={
moveY(pxsize){//移动box元素在y轴上的位置
box.style.transform = `translateY(${pxsize}px)`
},
zoom(size){// 缩放box元素
box.style.transform = `scale(${size})`
},
changeColor(color){//改变box元素的背景颜色
box.style.backgroundColor = color
},
changeOpacity(size){// 改变box元素的的不透明度
box.style.opacity = size
}
};
return {
// 运行对应的策略
run(type,data){
s[type](data)
},
// 添加新的策略
addStr(type,callback){
s[type] = callback
},
}
})();
box.addEventListener('click', ev =>{
Strategy.run('changeOpacity',0.78)
});
上面的代码是一个很简单的策略模式, 我们利用闭包来把所有的策略保存到对象中, 通过对应暴露两个运行策略和添加策略的接口,实现对策略的使用, run方法通过传入的type来获取对应的策略并运行对应的方法并传对应的参数, 通过addStr接口我们可以添加新的策略,提高了策略的扩展性, 较大得提高了代码的可读性.
- 场景二
// 玩家类
class Player {
constructor() {
// 保存消费总价
this.totalCost = 0;
//对应的消费等级
this.level = "C"
}
consume(price) {
// 计算消费的总价;
this.totalCost += price
let result = strategy.calc(this.level, price);
this.getLevel();
// 返回当消费的价格
return result
}
getLevel() {
// 设置当前消费等级
this.level = levelStrategy.calc(this.totalCost)
}
}
// 计算level 策略类
const levelStrategy = (function () {
let s = [{
maxTotalCost: 5000,
level: "S"
},
{
maxTotalCost: 3000,
level: "A"
},
{
maxTotalCost: 2000,
level: "B"
},
{
maxTotalCost: 0,
level: "C"
}
];
return {
// 计算当前消费所对应的等级
calc(totalCost) {
for (const v of s) {
if (totalCost >= v.maxTotalCost) {
return v.level
}
}
}
}
})()
// 折扣策略类
const strategy = (function () {
let s = {
S(price) {
return price * 0.85
},
A(price) {
return price * 0.9;
},
B(price) {
return price * 0.95;
},
C(price) {
return price;
}
};
return {
addSty(name, fn) {
s[name] = fn
},
//计算策略所定义最终价格的接口
calc(sty, price) {
if (s[sty]) {
return s[sty](price)
} else {
throw new Error('对应的优惠策略不存在')
}
}
}
})();
let player = new Player();
console.log(player.consume(5000));// 5000
console.log(player.consume(100));// 85
总结 : 当一个对象有多种行为, 并且需要动态的让对象在行为中选择一种行为时,此时使用策略模式就非常合适,大大地减轻了我们使用if...else所带来的复杂性和维护性.策略模式的实现就是通过把这些算法封装成一个类,然后通过指定的行为类型来获取出对应的行为并执行对应的操作,使得我们可以任意的进行替换我们想要的行为.极大提升了代码的灵活性和可扩展性.
网友评论