设计模式——状态模式
状态模式主要用来满足某个对象内部存在不同表现的需求场景。可以说是一种针对相似功能的类的进一步的封装。当这个状态对象接受到请求时,再将请求委托到内部类,根据内部定义好的实现逻辑返回结果到状态对象再表现出来。
面向对象思想具体实例
现在我们利用状态模式实现一个具有三种状态的灯,分别是弱光,强光,无光。灯的按钮被按下时,将在三种状态下依次切换。
其实这三种状态我们可以看成是三种不同的灯,只是具有相同的接口。那么我们先定义这三个类,并且赋予同样的原型方法buttonWasPressed表示内部逻辑实现。
let OffLightState = function(light) {
this.light = light;
}
OffLightState.prototype.buttonWasPressed = function() {
console.log('弱光');
this.light.setState(this.light.weakLightState);
}
let WeakLightState = function(light) {
this.light = light;
};
WeakLightState.prototype.buttonWasPressed = function() {
console.log('强光');
this.light.setState(this.ligth.strongLightState);
}
let StrongLightState = function(light) {
this.light = light;
}
let StrongLightState.prototype.buttonWasPressed = function() {
console.log('关灯');
this.light.setState(this.light.offLightState);
}
可以看到我们通过传递light对象对这三个类进行了包装,通过状态的切换来和不同类的内部逻辑产生联系。接下来只要实现上层类Light通过将请求委托到被包装的三个类实现不同状态间的调用即可。
const Light = function() {
this.offLightState = new OffLightState(this);
this.weakLightState = new WeakLightState(this);
this.strongLightState = new StrongLightState(this);
this.button = null;
};
Light.prototype.init = function() {
let button = document.createElement('button'),
self = this;
this.button = document.body.appendChild(button);
this.button = innerHTML = '开关';
this.currState = this.offLightState;
this.button.onclick = function() {
self.currState.buttonWasPressed();
}
};
Light.prototype.setState = function(newState) {
this.currState = newState;
};
至此就完成了一个状态模式的编写。可以看到我们通过将定义的上层对象light传入状态类的实例对象使得上层类持有对状态对象的引用。用户的请求委托给了状态对象,实际上是在上层对象中实现的。
无类思想改进
上例中我们为每种状态都定义了一个状态子类,但在JS中并不需要对象从类创建而来,我们可以通过函数借用的方法直接委托请求。改进如下:
const Light = function() {
this.currState = FSM.off; // 状态函数管理
this.button = null;
};
Light.prototype.init = function() {
let button = document.createElement('button');
let self = this;
button.innerHTML = '开关';
this.button = document.body.appendChild(button);
this.button.onclick = function() {
self.currState.buttonWasPressed.call(self); // 委托请求
}
};
const FSM = {
off: {
buttonWasPressed: function() {
console.log('弱光');
this.currState = FSM.weak;
}
},
weak: {
buttonWasPressed: function() {
console.log('强光');
this.currState = FSM.strong;
}
},
strong: {
buttonWasPressed: function() {
console.log('关灯');
this.currState = FSM.off;
}
}
};
小结
可以看出状态模式实际上就是对一个具有明显分支功能的对象的内部结构再构造,避免出现过多的条件分支,使得内部状态的切换更加自然,而且也可以简单的拓展新的分支。由于这些特点存在,使用场景也就很明显了。当一个对象的内部行为逻辑有明显的状态切换时就可以考虑使用状态模式重构。
-- EOF --