同事的【策略模式】比我高级这么多?我哪里比不过人家?

开发
我理解策略模式就是,在不同的条件下去做不用的事情,并且这些事情是不会互相影响的,我们可以把这些不同的事情封装起来。

大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心~

最近我在项目中遇到一个需求,就是需要根据一个人的这些条件:

  • 名字
  • 岁数
  • 体重

根据不同的这些条件去执行不同的函数,比如:

  • 林三心-20-160: 输出我叫林三心,我是个年轻人,我是个瘦子
  • 林三心-60-300: 输出我叫林三心,我是个老年人,我是个胖子

这种判断是需要嵌套判断的,情况非常多,写起代码非常麻烦,且可维护性很差,所以我第一时间想到了策略模式来解决,但是发现大部分网上的策略模式方案讲解都不太符合我这个需求。

最近我对策略模式又有新的理解,我想通过我自己的方式将这些知识分享给大家。

你认识策略模式吗?

我理解策略模式就是,在不同的条件下去做不用的事情,并且这些事情是不会互相影响的,我们可以把这些不同的事情封装起来。

就比如下面的简单例子,根据 name 的不同的值,去执行不同的代码:

上面的代码怎么优化呢?看过一些简单策略模式的朋友,肯定第一感觉就是使用对象去存储,其实在这个场景中,完全可以去这么做:

复杂情况呢?

上面的代码例子是非常简单的,但是如果是一些比较复杂的场景呢?比如我不止 name 了,我加了 age ,那么这样的 if 嵌套,你又该如何去用简单的 map 去解决呢?

有人说,那我这样去做,不就行了~

是,其实你非要去做也能做,无非就是麻烦点,但是如果我不止 name、age,我又加了 height、weight、username、phone 之类的判断条件,请问阁下又该如何应对呢?而且是嵌套的哦~

还有一种情况,就是如果我们并不是每一个分支的情况都需要去执行代码的,比如:

  • sunshine_lin:只需要关注 20、40岁 的情况
  • sanxin_lin:只需要关注 60岁 的情况
  • 林三心:只需要关注 20岁 的情况

或者哪天我想改变规则了,比如:我想改变一下,只关注 sunshine_lin 的 40岁 情况。

在遇到上述所说这些情况的时候,如果你还以上面的策略模式方案去解决问题,那么解决起来会非常棘手,可维护性也不太高,所以我们应该换一个方案~

换汤不换药

大方向上,还是用一个对象去映射,也就是不同条件映射到不同的执行代码,只不过呢,这个时候我们要把条件换一换,还是刚刚的例子:

换一种思路,我们使用一个集合去当条件,比如像这样子:

是的,这个所谓的集合就是所有判断条件组成的一个对象,把他转成字符串,当做策略的条件,这样是不是就看起来更加方便了?但其实是有坑的,比如下面这两种条件,其实就是同一个条件,但是因为序列化时会有顺序的问题,导致了两个相同的条件匹配不到同一个函数:

所以我们需要对条件对象进行排序,要保证这两个条件匹配到同一个函数,怎么做呢?我们要让他们顺序保持一直就行了!!需要利用到 Map 这个数据结构,Map 的 key 是有顺序的~

这样就保证了不同顺序的条件对象,能匹配到同一个函数了~

封装 + 可拓展性

上面的代码都是比较散的代码,如果想要代码更好的复用,肯定是需要进行封装,使用一个 class 去封装,并且你要考虑一些边界情况,比如:

  • 条件匹配不上,需要执行默认情况
  • 代码报错处理

想要更好地去完成这个方案,我们可以借助另一种设计模式发布订阅模式,具体代码请看下方,我建议大家要多看代码,多敲,从中领略到它到底有啥好处~

完整代码

class Strategy {
  map = new Map();

  constructor({ defaultCbs, errorCbs }) {
    // 默认
    this.map.set("default", defaultCbs ?? []);
    // 错误
    this.map.set("error", errorCbs ?? []);
  }

  // 获取条件key
  getCondition(condition) {
    const conditionMap = new Map();
    Object.keys(condition)
      .sort()
      .forEach((key) => {
        conditionMap.set(key, condition[key]);
      });
    return JSON.stringify(Object.fromEntries(conditionMap));
  }

  // 增加条件情况
  add(condition, conditionCbs) {
    const currentCondition = this.getCondition(condition);
    let cbs = this.map.get(currentCondition);
    if (!cbs) {
      this.map.set(currentCondition, []);
      cbs = this.map.get(currentCondition);
    }
    cbs.push(...conditionCbs);
  }

  // 执行条件情况
  do(condition) {
    const currentCondition = this.getCondition(condition);
    try {
      const cbs = this.map.get(currentCondition);
      if (cbs) {
        cbs.forEach((cb) => cb(JSON.parse(currentCondition)));
      } else {
        // 匹配不到则执行默认函数
        const defaultCbs = this.map.get("default");
        defaultCbs.forEach((cb) => cb(JSON.parse(currentCondition)));
      }
    } catch (e) {
      // 报错执行报错函数
      const errorCbs = this.map.get("error");
      errorCbs.forEach((cb) => cb(e));
    }
  }
}

const strategy = new Strategy({
  defaultCbs: [
    (v) => {
      console.log("这是默认情况", v);
    },
  ],
  errorCbs: [
    (e) => {
      console.log("这是错误情况", e);
    },
  ],
});
const condition = {
  name: "sunshine_lin",
  weight: 160,
};

// 此时还没有注册条件事件,所以输出默认事件
strategy.do(condition); 

// 添加条件函数
strategy.add(condition, [
  (v) => {
    console.log("事件1", v);
  },
  (v) => {
    console.log("事件2", v);
  },
]);

// 此时有条件事件了,输入:事件1 事件2
strategy.do(condition);

const condition2 = {
  name: "error_lin",
  weight: 1000000,
};

// 可以增加报错条件
strategy.add(condition2, [
  (v) => {
    throw new Error("我超重啦!!!!");
  },
]);

// 报错,输出:我超重啦!!!!
strategy.do(condition2)
责任编辑:赵宁宁 来源: 前端之神
相关推荐

2017-08-11 14:21:33

软件开发前端框架

2024-04-02 08:41:10

ArrayListSubList场景

2023-07-17 08:21:52

漏洞版本项目

2021-05-11 07:42:59

BeanSpring属性

2020-12-22 09:37:56

IT技术数据

2018-06-26 15:00:24

Docker安全风险

2023-11-13 08:49:54

2024-02-20 08:09:51

Java 8DateUtilsDate工具类

2018-02-01 07:16:08

布线电线线路

2013-01-15 09:41:45

编程语言

2017-12-21 19:38:50

润乾中间表

2021-01-14 05:08:44

编译链接

2022-07-26 23:43:29

编程语言开发Java

2021-01-29 08:52:10

App微信移动应用

2017-07-04 14:01:40

机房机柜

2016-05-12 10:27:17

信锐Wi-Fi网络

2017-07-12 08:20:32

闪存用途企业

2020-06-01 08:04:18

三目运算符代码

2020-08-31 06:43:13

Redis集群模式

2020-11-20 10:22:34

代码规范设计
点赞
收藏

51CTO技术栈公众号