从业务场景谈策略模式

154 阅读3分钟

场景

现在有一个积分活动,活动状态分为积分不足、未开始、已开始、立即参与、已抽奖、已中奖、未中奖、已结束,后端返回的字段为

  • joinState 活动状态0 积分不足 1 可参与 2 从别处领取 3已截止 4未开始
  • state 开奖状态 1未开奖 2已开奖
  • receiveState 参与状态 0点击详情 1点击参与
  • collectionState 状态 1待开奖 2中奖 3未中奖

试想一下如果现在你要根据后端返回的这几个字段来显示不同的活动状态,你会怎么做

你可能会这样写:

// 当活动状态为1且开奖状态为1且receiveState为1的时候 显示立即参与
if(joinState == 1 && state == 1 && receiveState == 1){
    // 立即参与
}
// 当活动状态为1且开奖状态为1且collectionState为2的时候 显示中奖
if(joinState == 1 && state == 1 && collectionState == 2){
   //  中奖
}

这样做的缺点:

  1. 代码冗余,当条件越来越多时,if判断也会越来越多,往往写到后来自己都看不下去了
  2. 扩展性差,如果后面多加了一个条件,比如说还要判断是否是会员,那基本上所有的if判断都要重新写,工作量可想而知
  3. 后期维护困难,如果后面判断逻辑变了,那要改的话也是一件很头疼的事情,牵一发而动全身

那有没有更优雅的解决方案呢?

解决方案

首先,我们来回顾下Map的特性

Map 数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

也就是说Map的Key是可以为任意类型的,所以我们可不可以把这些条件写在key里,把要处理的条件判断写在value里,然后通过遍历去查找对应的方法。那具体要怎么做呢?

我们可以在key里面写个正则表达式,通过正则表达式去匹配相应的状态,这样就能大大缩减代码的复杂性以及增加状态的可维护性

首先定义变量,变量的值为控制活动状态的几个字段组成的字符串

const status = `${joinState}${state}${receiveState}${collectionState}`;

接着定义策略,根据我们获得的变量就可以顺利匹配出当前的状态了

let type = EStatusType.Begin;
const statusMap = new Map([
    [/^11[1,2,3]0/, EStatusType.Begin],
    [/^11[1,2,3]1/, EStatusType.Joined],
    [/^12[1][0,1]/, EStatusType.WinNotReceived],
    [/^12[2][0,1]/, EStatusType.Win],
    [/^12[3][0,1]/, EStatusType.WinTimeOut],
    [/^13[1,2,3][0,1]/, EStatusType.NotWin],
    [/^2/, EStatusType.ReceivedFromOther],
    [/^3/, EStatusType.End],
    [/^4/, EStatusType.NotBegin],
]);
for (const [keyReg, value] of statusMap.entries()) {
    if (keyReg.test(myStatus)) {
        type = value;
    }
}

这种解决方法就可以归类到设计模式之中的策略模式,它的应用场景其实很多,像订单,活动都可以用到这种模式

策略模式 (Strategy Pattern)就是定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。

希望大家可以学以致用