Easy to handle JS strategy mode!

Easy to handle JS strategy mode!

·

3 min read

Definition

The Strategy pattern is a common and effective design pattern. It refers to defining a set of algorithms, encapsulating them one by one, and making them interchangeable. The essence of the Strategy pattern is to separate the use of algorithms from their implementation. A basic strategy pattern has two parts.

  1. a set of policy classes that encapsulate the specific algorithm inside and are responsible for its concrete implementation.
  2. an environment class Context, which accepts requests from clients and delegates them to a particular policy class.

Advantages and disadvantages

The Strategy pattern has the following advantages.

  • Uses techniques such as combination, delegation, and polymorphism to effectively avoid multiple conditional selection statements.
  • Provides perfect support for the open-close principle, and is easy to understand and extend using policy branching functions.
  • The combination, delegation approach also gives Context the basic ability to execute algorithms.
  • Reusability is relatively high.

The disadvantages of the Strategy pattern are not so obvious, mainly in that the application needs to maintain more policy objects, but essentially the advantages outweigh the disadvantages.

Example

In Javascript, functions are objects themselves as first-class citizens, so we use objects to implement the Strategy Pattern.

// part 1
var strategies = {
  S: function(salary) {
    return salary * 4;
  },
  A: function(salary) {
    return salary * 3;
  },
  B: function(salary) {
    return salary * 2;
  },
}

// part 2
var calculateBouns = function(level, salary) {
  return strategies[level](salary);
};

console.log(calculateBouns('S', 2000));
console.log(calculateBouns('A', 800));

Scenarios

Form validation

In daily form interaction, we will encounter various input items bound to the corresponding form validation rules, if each input item one by one to write the corresponding rules will be time-consuming and redundant, we can use strategy pattern to modify.

var strategies = {
  isNonEmpty(value, errorMsg) {
    if(value === '' || value == null) {
      return errorMsg;
    }
  },
  minLength(value, length, errorMsg) {
    if(value.length < length) {
      return errorMsg;
    }
  },
  isMobile(value, errorMsg) {
    if(! /1[3][5][8][0-9]{9}$/.test(value)) {
      return errorMsg;
    }
  },
}

After completing the rule mapping table for the form, create a new Validator class for rule validation. The Validator class here acts as a Context, responsible for receiving user requests and delegating them to strategies to match the corresponding rules.

var Validator = function() {
  this.cache = [];
}

Validator.prototype.add = function(value, rule, errorMsg) {
  var arr = rule.split(':');
  this.cache.push(
    function() {
      var stratery = arr.shift();
      arr.unshift(value);
      arr.push(errorMsg); // [44, "isMobile", 'phone number not in correct format']
      return strategies[stratery].apply(this, arr)
    }
  )
}

Validator.prototype.start = function(value, rule, errorMsg) {
  for(let i = 0; i < this.cache.length; i++) {
    var validator = this.cache[i];
    var msg = validator();
    if(msg) {
      return msg
    }
  }
}

// Use
var validator = new Validator();

validator.add('13136199370', 'isMobile', 'Phone number is not in correct format');
validator.add('12', 'minLength: 6', 'Password length cannot be less than 6 digits');

var errMsg = validator.start();
console.log(errMsg);

Did you find this article valuable?

Support Jweboy's blog by becoming a sponsor. Any amount is appreciated!