JS设计模式-策略模式

105 阅读1分钟

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

将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。

一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程;第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。

比如使用策略模式实现一个表单验证的功能:

先将策略名和要执行的策略方法列出来:

interface IValidateFunc {
  (value: string, errorMessage: string, ...args: unknown[]): string | void;
}

// 策略名
const RULE_KEYS_MAP = {
  isNotEmpty: "isNotEmpty",
  isMobile: "isMobile",
  minLength: "minLength",
};

// 要执行的策略方法
const validateIsNotEmpty: IValidateFunc = function (
  value: string,
  errorMessage: string
) {
  if (!value) {
    return errorMessage;
  }
};
const validateIsMobile = function (
  value: string,
  errorMessage: string
): string | void {
  if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
    return errorMessage;
  }
};
function validateMinLength(
  value: string,
  length: number | string,
  errorMessage: string
): string | void {
  console.log(value.length, length);
  if (value.length < Number(length)) {
    return errorMessage;
  }
}

然后实现策略对象,将策略名作为对象的键,策略方法作为对象的值,实现映射:

const strategis: {
  [key: string]: IValidateFunc;
} = Object.keys(RULE_KEYS_MAP).reduce((prev, key) => {
  let func = null;
  switch (key) {
    case RULE_KEYS_MAP.isNotEmpty:
      func = validateIsNotEmpty;
      break;
    case RULE_KEYS_MAP.isMobile:
      func = validateIsMobile;
      break;
    case RULE_KEYS_MAP.minLength:
      func = validateMinLength;
    default:
      break;
  }
  func && (prev[key] = func);
  return prev;
}, {});

创建一个上下文类,用于管理和调用策略。

class Validator {
  strategis: {
    validateFunc: IValidateFunc;
    value: string;
    ruleParams: unknown[];
    errorMessage: string;
  }[];
  constructor() {
    this.strategis = [];
  }
  add(value: string, rule: string, errorMessage: string) {
    const [ruleKey, ...ruleParams] = rule.split(":");
    this.strategis.push({
      validateFunc: strategis[ruleKey],
      value,
      ruleParams,
      errorMessage,
    });
  }
  run() {
    this.strategis.forEach((strategy) => {
      const { validateFunc, value, ruleParams, errorMessage } = strategy;
      const message = validateFunc(value, errorMessage, ruleParams);
      if (message) {
        console.error(message);
      }
    });
  }
}

实现了上面的功能后,下面模仿用户的使用,调用上下文类,配置策略,执行表单验证:

const validator = new Validator();

validator.add("13122224444", RULE_KEYS_MAP.isMobile, "电话号码格式不对");
validator.add("", RULE_KEYS_MAP.isNotEmpty, "这里不能为空");
validator.add("12345", `${RULE_KEYS_MAP.minLength}:6`, "最小长度要为6");

validator.run();

执行结果:

image.png