策略模式

2020-11-04  本文已影响0人  小宇cool

1. 策略模式

1.1 定义

策略模式(Strategy):策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,且具有一定的独立性, 不会随客户端的变化而变化.

一系列的算法, 可以相互醍醐, 也就是说为了同一个目的, 可能采取的算法不一样, 同时要体现出独立性.策略模式将这些算法封装成一个一个的类,可以任意的替换

1.2 作用

  1. 减轻当代码中过多if...else带来的复杂度和难以维护的问题.
  2. 让一个对象可以动态得在许多行为中选择一种行为.
  3. 提高代码的可扩展性,让算法可以自由切换.

1.3 应用场景

// 操作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所带来的复杂性和维护性.策略模式的实现就是通过把这些算法封装成一个类,然后通过指定的行为类型来获取出对应的行为并执行对应的操作,使得我们可以任意的进行替换我们想要的行为.极大提升了代码的灵活性和可扩展性.

上一篇下一篇

猜你喜欢

热点阅读