前言
状态模式应用比较广泛,根据状态改变行为,可以说在我们代码中常常会用到,状态机也是基于如此实现,比如我们想根据状态更改class等等。以下是一个控制灯开关的demo
function Light(){
this.state = "off";
this.button = null;
}
Light.prototype.init = function(){
const button = document.createElement("button");
button.innerHTML = "开关";
this.button = document.appendChild(button);
const _self = this;
this.button.addEventListener("click",function(){
_self.buttonPress();
},false);
}
Light.prototype.buttonPress = function(){
if(this.state==="off"){
console.log("灯打开了!");
this.state = "turn";
}else{
console.log("灯关上了!");
this.state = "off";
}
}
上述代码完成任务完全没问题,但是如果此时需要增加几个状态,比如弱光、强光,我们势必会添加很多很多if…else,并且会深入逻辑内部,这显然是不符合开放-封闭原则的。上述代码,在我之前写的程序中也会非常多,这时我们需要使用状态模式对状态进行管理
JavaScript中的状态模式
状态模式强调将状态封装为类,我们平常都是将行为进行封装,而状态模式是对属性(状态)进行封装,这样状态就不会与逻辑进行耦合,我们更换、添加状态时就会更加的方便,现在使用状态模式对开关灯demo进行改写
function Light() {
this.Turn = new Turn(this);
this.Off = new Off(this);
this.button = null;
}
/* 打开状态 */
function Turn(light) {
this.light = light;
}
Turn.prototype.buttonPress = function () {
console.log("灯关上了!");
// 当前状态为关闭
this.light.setState(this.light.Off);
}
/* 关闭状态 */
function Off(light) {
this.light = light;
}
Off.prototype.buttonPress = function () {
console.log("灯开上了!");
// 当前状态为打开
this.light.setState(this.light.Turn);
}
Light.prototype.init = function () {
const button = document.createElement("button");
button.innerHTML = "开关";
this.button = document.body.appendChild(button);
this.currState = this.Off;
const _self = this;
this.button.addEventListener("click", function () {
_self.currState.buttonPress();
}, false);
}
Light.prototype.setState = function (newState) {
this.currState = newState;
}
const light = new Light();
light.init();
一个状态就是一个类,这时我们想添加状态只需要增加一个状态类,修改一部分逻辑即可(顺序和在内部实例化一个状态类)。所有状态类都需要实现相应的触发方法,在本例中为buttonPress
,这在面向对象语言中使用抽象类即可
public abstract class State {
abstract void buttonPress();
}
但是在JavaScript中并没有接口或者抽象类的概念,所以我们可以使用抛出错误的形式人为的规定,必须实现相应的方法
function State(){ }
State.prototype.buttonPress = function(){
throw new Error("必须重写buttonPress方法");
}
function Turn(light){
this.light = light;
}
Turn.prototype = new State();
状态机
状态机是一种统一管理状态的实现,在JavaScript中实现状态机非常的容易,并且实用
/* 状态机 */
const FSM = {
off:{
buttonPress(){
console.log("灯开上了!");
this.currState = FSM.on;
}
},
on:{
buttonPress(){
console.log("灯关上了!");
this.currState = FSM.off;
}
}
}
function Light() {
this,currState = FSM.off;
this.button = null;
}
Light.prototype.init = function () {
const button = document.createElement("button");
button.innerHTML = "开关";
this.button = document.body.appendChild(button);
const _self = this;
this.button.addEventListener("click", function () {
_self.currState.buttonPress();
}, false);
}
const light = new Light();
light.init();
优缺点
状态模式将动作与相应的行为和状态进行解耦,但是会添加比较多的状态类,并且状态之间是耦合在一起的,如果想修改顺序还是需要深入代码内部,状态机对所有状态进行管理,在JavaScript中更加容易实现和实用