设计模式:策略模式

策略模式

我认为的封装模式,就是封装一系列方法;这些方法的共同点就是:输入输出相同;而我们在不同地条件只是需要简单地将中间的转换方法(即策略)进行更换,就可以达到不同条件下的目标。

策略模式常用的场景就是个表单验证。我们就拿这个表单验证说话好了。

表单验证

为了化简问题,我们取消从DOM中取表单的值这一过程;我们就假设这一过程最后取到的值如下吧:

var data = {
  firstName: "Super",
  lastName: "Man",
  age: "unknown",
  userName: "o_O"
}

这当然是随便就能做到对吧……而且这很符合单一职责原则,即我们可以通过一个函数,这个函数只需要将DOM中表单的value总和成这样一个对象。

接着我们要写一个验证器;我们先用个最简单的object形式来写好了。我们的第一个需求就是这个验证器是可以配置的。这个配置可以用来配置需要检测表单中的哪几项以及检测这几项应该使用的“策略”。

var validator = {};

validator.config = {
  firstName: 'isNonEmpty',
  age: 'isNumber',
  userName: 'isAlphaNum'
}

通过这个配置,我们想表达的是:我们想通过isNonEmpty作为firstName的验证方法;我们希望通过isNonEmpty(data.firstName)来验证真伪。

没有添加至config我们可以默认认为是不需要做验证的;当然我们也可以加入多个验证方法比如:

validator.config.lastName = ['isNonEmpty', 'isAlphaNum'];

当然这里为了简单点我们就假设没有数组类型的验证方法好了。

接下来我们编写这些验证策略;我们在validator中再添加一项strategies来作为策略。

validator.strategies = {
  isNonEmpty: {
    validate: function (value) {
      return value !== "";
    },
    instructions: "the value cannot be empty."
  },
  isNumber: {
    validate: function (value) {
      return !isNaN(value);
    },
    instructions: "the value must be a valid number."
  },
  isAlphaNum: {
    validate: function (value) {
      return !/[^a-z0-9]/i.test(value);
    },
    instructions: "随便写吧……"
  }
}

这样我们编写了验证器的验证策略,这还是很容易进行添加新的策略的。

然后我们的核心,就是接下来这个验证函数。注意这个时候,这个验证函数的输入已经确定了,表单数据data和策略strategies(突然觉得策略也没必要挂载验证器之下),验证函数将这俩作为输入,返回验证结果。只是在这个过程中,根据data选择对应的策略函数并执行而已。

validator.test = function (data) {
  for (var i of data) {
    var value = data[i],
        op = this.config[i],
        fn = this.strategies[op];
    
    if (!op) {
      // 不需要验证
      continue;
    }

    if (!fn) {
      // 没实现需要的方法;报错吧
    }

    if (!fn(value)) {
      // 表单验证失败,该怎么做在哪里写处理错误的代码自己决定吧
      return false;
    }

  }
  return true;
}

策略模式通过将数据、策略、验证函数分离开,让每一个部分保持“单一职责原则”;有种MVC的感jio。data即代表Modelstrategies代表ControllerView我们则是在test函数中实现的;虽然View层不纯净,当然我们可以让它纯净……

这样我们三层中就只需要关心各个负责的任务,而不再需要糅合地去写代码了。

你可能感兴趣的:(设计模式:策略模式)