Learn the state patterns of JavaScript design patterns

  • 2020-11-26 18:41:13
  • OfStack

The key to the state pattern is to distinguish the internal state of things. The change of the internal state of things often brings the change of the behavior of things.

When the light is on, press the switch and the light will switch to the off state. Push the switch once more and the light will turn on again. The same switch behaves differently in different states.

1. Finite state machine

The total number of states (state) is finite. At any one time, you're only in one state. Under certain conditions, there is a transition from one state (transition) to another.

Allows an object to change its behavior when its internal state changes. The object appears to modify its class.
Explanation:
(1) Encapsulate the state into independent classes, and delegate the request to the current state object. When the internal state of the object changes, different behavior changes will be brought.
(2) The objects used have distinct behaviors in different states (delegation effect)

When it comes to encapsulation, 1 generally gives priority to the behavior of the encapsulated object over the state of the object.
But in a state pattern, the opposite is true. The key is to encapsulate each state of things into a separate class.

Example 2.

Laminator (weak light?) > Light � > Turn off the light) cycle


//  Turn off the lights 
var OffLightState = function(light) {
  this.light = light;
};
//  Weak light 
var OffLightState = function(light) {
  this.light = light;
};
//  Bright light 
var StrongLightState = function(light) {
  this.light = light;
};

var Light = function(){
  /*  Switch state  */
  this.offLight = new OffLightState(this);
  this.weakLight = new WeakLightState(this);
  this.strongLight = new StrongLightState(this);
  /*  Quick off button  */
  this.button = null;
};
Light.prototype.init = function() {
  var button = document.createElement("button"),
    self = this;
  this.button = document.body.appendChild(button);
  this.button.innerHTML = ' switch ';
  this.currentState = this.offLight;
  this.button.click = function() {
    self.currentState.buttonWasPressed();
  }
};
//  Let abstract methods of an abstract parent class be thrown directly 1 An exception (to avoid unimplemented state subclasses) buttonWasPressed Methods) 
Light.prototype.buttonWasPressed = function() {
  throw new Error(" Of the parent class buttonWasPressed Methods must be overridden ");
};
Light.prototype.setState = function(newState) {
  this.currentState = newState;
};

/*  Turn off the lights  */
OffLightState.prototype = new Light(); //  Inherited abstract class 
OffLightState.prototype.buttonWasPressed = function() {
  console.log(" Turn off the lights! ");
  this.light.setState(this.light.weakLight);
}
/*  Weak light  */
WeakLightState.prototype = new Light();
WeakLightState.prototype.buttonWasPressed = function() {
  console.log(" Weak light! ");
  this.light.setState(this.light.strongLight);
};
/*  Bright light  */
StrongLightState.prototype = new Light();
StrongLightState.prototype.buttonWasPressed = function() {
  console.log(" Bright light! ");
  this.light.setState(this.light.offLight);
};

PS: Note supplement
The OffLightState, WeakLightState, StrongLightState constructors must be brought forward.


new A("a");
var A = function(a) {
  console.log(a)
}

new B("b");
function B(b) {
  console.log(b);
}

Function declarations are promoted before normal variables.

3. Performance optimization points

(1) How to manage the creation and destruction of state objects?
The first is to create and then destroy state objects only when they are needed (state objects are large and preferred),
The other is that 1 creates all state objects at the beginning and never destroys them (state changes are frequent).
(2) Share 1 state object by sharing meta-mode.

JavaScript version of the state machine

(1) Delegate the request directly to a literal object for execution through the Function.prototype.call method


//  The state machine 
var FSM = {
  off: {
    buttonWasPressed: function() {
      console.log(" Turn off the lights ");
      this.button.innerHTML = " Under the 1 Push me to turn on the light ";   //  This is a Light Attributes on!! 
      this.currState = FSM.on;            //  This is a Light Attributes on!! 
    }
  },
  on: {
    buttonWasPressed: function() {
      console.log(" Turn on the light ");
      this.button.innerHTML = " Under the 1 Press me to turn off the light ";
      this.currState = FSM.off;
    }
  },
};

var Light = function() {
  this.currState = FSM.off;  //  Set current state 
  this.button = null;
};

Light.prototype.init = function() {
  var button = document.createElement("button");
  self = this;

  button.innerHTML = " Have to turn off the lights ";
  this.button = document.body.appendChild(button);
  this.button.onclick = function() {
    //  Request delegation to FSM The state machine 
    self.currState.buttonWasPressed.call(self);
  }

}

var light = new Light();
light.init();

(2) Use delegate function


var delegate = function(client, delegation) {
  return {
    buttonWasPressed: function() {
      return delegation.buttonWasPressed.apply(client, arguments);
    }
  };
};

//  The state machine 
var FSM = {
  off: {
    buttonWasPressed: function() {
      console.log(" Turn off the lights ");
      this.button.innerHTML = " Under the 1 Push me to turn on the light ";
      this.currState = this.onState;
    }
  },
  on: {
    buttonWasPressed: function() {
      console.log(" Turn on the light ");
      this.button.innerHTML = " Under the 1 Press me to turn off the light ";
      this.currState = this.offState;
    }
  },
};

var Light = function() {
  this.offState = delegate(this, FSM.off);
  this.onState = delegate(this, FSM.on);
  this.currState = this.offState; //  Set current state 
  this.button = null;
};

Light.prototype.init = function() {
  var button = document.createElement("button");
  self = this;

  button.innerHTML = " Have to turn off the lights ";
  this.button = document.body.appendChild(button);
  this.button.onclick = function() {
    //  Request delegation to FSM The state machine 
    self.currState.buttonWasPressed();
  }
}

var light = new Light();
light.init();

I hope this article has been helpful in learning javascript programming.


Related articles: