策略模式

定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换

策略模式一般分为策略类(封装具体算法,负责策略的具体逻辑计算) + 环境类(接收用户请求,把请求委托给某一策略),将算法的使用和算法的实现分离开来,消除大量条件分支语句。

在具体应用中,我们常常会遇到根据状态,选择不同的处理逻辑。通常会用if-else来处理,或者switch。但是大量业务逻辑和状态判断封装在一起,函数显得冗余又杂乱。
image.png
那应该怎么做?
以超市打折的场景为例:

当价格类型为“预售价”时,满 100 - 20,不满 100 打 9 折
当价格类型为“大促价”时,满 100 - 30,不满 100 打 8 折
当价格类型为“返场价”时,满 200 - 50,不叠加
当价格类型为“尝鲜价”时,直接打 5 折
  1. 首先,对每种状态的逻辑处理封装成函数(对应策略类)。然后判断类型,选择处理函数(对应环境类)。
// 处理预热价
function prePrice(originPrice) {
  if(originPrice >= 100) {
    return originPrice - 20
  } 
  return originPrice * 0.9
}

// 处理大促价
function onSalePrice(originPrice) {
  if(originPrice >= 100) {
    return originPrice - 30
  } 
  return originPrice * 0.8
}

// 处理返场价
function backPrice(originPrice) {
  if(originPrice >= 200) {
    return originPrice - 50
  }
  return originPrice
}

// 处理尝鲜价
function freshPrice(originPrice) {
  return originPrice * 0.5
}

// 处理新人价
function newUserPrice(originPrice) {
  if(originPrice >= 100) {
    return originPrice - 50
  }
  return originPrice
}

function askPrice(tag, originPrice) {
  // 处理预热价
  if(tag === 'pre') {
    return prePrice(originPrice)
  }
  // 处理大促价
  if(tag === 'onSale') {
    return onSalePrice(originPrice)
  }

  // 处理返场价
  if(tag === 'back') {
    return backPrice(originPrice)
  }

  // 处理尝鲜价
  if(tag === 'fresh') {
     return freshPrice(originPrice)
  }
  
  // 处理新人价
  if(tag === 'newUser') {
     return newUserPrice(originPrice)
  }
}

但是,代码看起来好像还是很冗余,并且没有实现“对扩展开放,对修改封闭”的效果。其中在判断类型时还是采用多个if-else语句来实现与处理函数的映射关系,那么在 JS 中,有没有什么既能够既帮我们明确映射关系,同时不破坏代码的灵活性的方法呢?答案就是对象映射!

  1. 把逻辑处理函数封装在一个对象
// 定义一个询价处理器对象
const priceProcessor = {
  pre: originPrice => {
    if (originPrice >= 100) {
      return originPrice - 20;
    }
    return originPrice * 0.9;
  },
  onSale:originPrice => {
    if (originPrice >= 100) {
      return originPrice - 30;
    }
    return originPrice * 0.8;
  },
  back: originPrice => {
    if (originPrice >= 200) {
      return originPrice - 50;
    }
    return originPrice;
  },
  fresh: originPrice => {
    return originPrice * 0.5;
  },
};
  1. 当需要某个类型对应处理函数时,可直接调用对象方法
function askPrice(tag, originPrice) {
  return priceProcessor[tag](originPrice)
}
  1. 如果想新增策略,只需要给对象添加一个方法
priceProcessor.newUser = function (originPrice) {
  if (originPrice >= 100) {
    return originPrice - 50;
  }
  return originPrice;
}

总结:在日常使用中,如果有大量状态判断以及逻辑处理,可以采用策略模式,将状态判断以及逻辑处理拆分,消除大量条件分支语句,同时实现“对扩展开放,对修改封闭”的原则。不要做if-else侠啦!


Lingo
18 声望7 粉丝