title: JavaScript设计模式之策略模式 date: 2021-06-05 16:00:00 updated: 2021-06-05 16:00:00 photos:

  • https://img.yzmblog.top/blog/article_policymode.png tags:
  • 前端
  • Javascript
  • 设计模式 categories:
  • Javascript
  • 设计模式 excerpt: 本文主要介绍的是设计模式中的单例模式在JavaScript中的实现和应用。

策略模式定义

我们在使用一些导航软件是,如果从 A 地到 B 地,导航软件会根据不同的条件使用不同的算法计算 A 地到 B 地的路径,但是最终要达到目的的一样的。这就是策略模式的体现。

策略模式就是定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换。

举个例子:在使用导航系统的时候,可以根据不同的条件去匹配不同的路径。那么可以这样去实现:

// 路径算法类A
function PathPolicyA() {}
PathPolicyA.prototype.calculate = function (type) {
  return "policyA";
};

// 路径算法类B
function PathPolicyB() {}
PathPolicyB.prototype.calculate = function (type) {
  return "policyB";
};

// 路径类
function Path() {
  this.path = null;
  this.policy = null;
}

Path.prototype.setPolicy = function (policy) {
  this.policy = policy;
};

// 根据不同类型获取不同的路径
Path.prototype.getPath = function () {
  return this.policy.calculate();
};

const p = new Path();

p.setPolicy(new PathPolicyA());
console.log(p.getPath()); // policyA

p.setPolicy(new PathPolicyB());
console.log(p.getPath()); // policyB

上面代码是一个传统面向对象语言的策略模式实现,它通过setPolicy设置不同的策略,再通过getPath调用对应策略类的calculate计算方法,最终返回路径。

JavaScript 的策略模式

上面代码虽然实现了策略模式,但是上面代码在 JS 中实现似乎显得有点笨重。JavaScript 创建对象非常简答,而且对象里面可以是一个函数。这样只需定义一个对象就可以解决上面的问题:

var policyObj = {
  A: () => "policyA",
  B: () => "policyB",
};
function getPath(policyObj, type) {
  if (policyObj[type] && typeof policyObj[type] === "function") {
    return policyObj[type]();
  }
  return "policy is not found";
}

console.log(getPath(policyObj, "A")); // policyA
console.log(getPath(policyObj, "B")); // policyB

这段代码与上面的方法作用是一致的,而且这段代码看上去是更为简洁,我们只需定义一个对象装入所有的策略,在根据不同的条件去调用不同的方法。
上面代码都体现了,策略模式的核心:定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换

利用策略模式制作表单验证

从定义看来,似乎策略模式是用来封装算法的,其实不然,我们也可以用它来做一些扩展,封装一些业务规则,比如表单验证,下面就用策略模式来实现一个表单验证吧~

var policy = {
  // 必填校验
  isEmpty: ({ val }) => !!val,
  // 最大长度校验
  maxLength: ({ maxLen, val }) => val.length < maxLen,
  //纯数字校验
  isNumber: ({ val }) => /^[0-9]*$/.test(val),
};

function varifyForm(formData, formRule) {
  // 循环表单对象
  for (let x in formData) {
    // 字段有定义规则才进行验证
    if (formRule[x]) {
      const tmpVal = formData[x];
      // 循环验证规则
      for (let rule of formRule[x]) {
        // 有定义的策略才验证
        if (policy[rule.type]) {
          const param = { ...Object.assign(rule.param || {}, { val: tmpVal }) };
          const isAccept = policy[rule.type](param);
          if (!isAccept)
            return {
              accept: false,
              msg: rule.errMsg || `${x} varify fail`,
            };
        }
      }
    }
  }
  return {
    accept: true,
    msg: "",
  };
}

// 定义测试用例
var form1 = {
  a: null,
};
var form2 = {
  a: 213213123,
};
var form3 = {
  a: "d212",
};
var rules = {
  a: [
    {
      type: "isEmpty",
      errMsg: "a is Empty",
    },
    {
      type: "maxLength",
      errMsg: "a is too long",
      param: { maxLen: 5 },
    },
    {
      type: "isNumber",
      errMsg: "a is not a number",
    },
  ],
};

console.log(varifyForm(form1, rules)); // a is Empty
console.log(varifyForm(form2, rules)); // a is too long
console.log(varifyForm(form3, rules)); // a is not a number

上面代码中,policy是一个定义策略的对象,varifyForm验证表单的主方法,通过传入表单数据表单字段验证规则,验证每个字段所定义的规则。最终返回验证结果。

聊聊 JavsScript 中的策略模式

在 JavaScript 中,函数作为一等对象,策略模式在这里跟原型模式一样,它已经融入了 JavaScript 语言本身。虽然它在 JavaScript 中是一种相对“透明”的模式,但是了解策略模式对我们设计函数,了解 JavaScript 有一定的帮助。

使用策略模式也有一定有优点:

1. 利用委托,组合等技术,可以有效避免条件选择语句。
2. 算法独立封装在一个对象或类中,更容易切换,理解和扩展。

小结

本文主要介绍了策略模式的概念和优点,在 JavaScript 中使用策略模式的例子。

策略模式是定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换

JavaScript 设计模式其他文章
1.原型模式
2.设计模式之单例模式

若您觉得文章对你有帮助,可以点一个赞鼓励一下作者,若想了解更多 JavaScript 或者 node 知识可以点击这里

参考

  1. JavaScript 设计模式与开发实践