策略模式

162 阅读2分钟

背景

抽象:需要不同场景执行不同的逻辑时。

具象:比如运算符,需要加数时,使用相加逻辑,乘法类似。

分析

ifswitch都可以实现这个目的,比如

const executor = (type: string, ops1: number, ops2: number) => {
  if (type === "add") {
    return ops1 + ops2;
  } else if (type === "mul") {
    return ops1 * ops2;
  } else {
    throw err;
  }
};

问题:如果我要拓展除法,那我得在 executor 里继续补充判断逻辑执行逻辑,这个 executor 明显是很多人会编辑的模块,当逻辑都杂糅在此处时,代码就会耦合,明显不符合开闭原则

解决方案

我们将执行逻辑先剥离出来

const add = (ops1: number, ops2: number) => {
  return ops1 + ops2;
};

const mul = (ops1: number, ops2: number) => {
  return ops1 * ops2;
};

const executor = (type: string, ops1: number, ops2: number) => {
  if (type === "add") {
    return add(ops1, ops2);
  } else if (type === "mul") {
    return mul(ops1, ops2);
  } else {
    throw err;
  }
};

这样,我们在重构或实现新的执行逻辑时,就和executor无关了

接下来,我们将判断逻辑也剥离,在需要用不同执行逻辑的地方,使用不同的执行逻辑, 我们定义一个执行者,给它传入什么执行逻辑,它就执行什么

class Executor {
  run: () => void;
  contructor() {}
  setRun(run) {
    this.run = run;
  }
  execute(...arguments) {
    this.run(...arguments);
  }
}
const calculator = new Executor();

// 我们可以这样使用
calculator.setRun(add);
let rsl = calculator.exec(1, 2);

// 也可以这么使用
if (type === "mul") {
  calculator.setRun(mul);
  rsl = calculator.exec(1, 2);
}
if (type === "add") {
  calculator.setRun(add);
  rsl = calculator.exec(1, 2);
}

这给我们了很多好处

  1. 很大的灵活性,而不是所有的判断逻辑全得写在 executor 函数中
  2. 提供了 Executor 这个类的范式,在多人开发中有一个规范

但是,我们并不清楚执行逻辑是什么类型的逻辑,这很被动,我们需要定义这个类型,重新拿回主动权

对于我们上面定义的 calculator,我们能知道它上用来执行两数处理的,所以我们可以定义 执行逻辑 的类型

class Run {
  run: (ops1: number, ops2: number) => number;
}

所有的执行逻辑的定义都得继承自Run

class Add extends Run {
  run(ops1: number, ops2: number) {
    return ops1 + ops2;
  }
}
class Mul extends Run {
  run(ops1: number, ops2: number) {
    return ops1 * ops2;
  }
}

这样我们以后写新的执行逻辑时,就有一个规范了。

比如设计一个减法的逻辑,我们只需要

class Sub extends Run {
  run(ops1: number, ops2: number) {
    return ops1 - ops2;
  }
}
const calculator = new Executor();
calculator.setRun(new Sub());
calculator.execute(1, 2);

好啦,这就是一个策略模式的原型啦,我们将执行逻辑 = Strategy来表达,而Executor = Context来表达。

如下

class Strategy {
  execute: (ops1: number, ops2: number) => number;
}
class Context {
  strategy: Strategy;
  constructor(strategy: Strategy) {
    this.strategy = strategy;
  }
  setStrategy(strategy: Strategy) {
    this.strategy = strategy;
  }
  execute(ops1: number, ops2: number) {
    return this.strategy.execute(ops1, ops2);
  } 
}
const calculator = new Context(new Add());
calculator.execute(1, 2);
calculator.setStrategy(new Mul());
calculator.execute(1, 2);
calculator.setStrategy(new Sub());
calculator.execute(1, 2);

这就是一个完整的策略模式啦~~~

结尾

各位看官,给个赞赞吧~~~~