状态模式的基础
定义:状态模式(State)定义一个对象,这个对象可以通过管理其状态从而使得应用程序作出相应的变化。
状态模式是一个非常常用的设计模式,它主要有两个角色组成:
(1)环境类:拥有一个状态成员,可以修改其状态并作出相应反应。
(2)状态类:表示一种状态,包含其相应的处理方法
作用:状态模式就是一种适合多种状态场景下的设计模式。使用状态模式可以让代码更加清晰,提高应用程序的维护性和扩展性。
使用场景:文件下载(开始、暂停、完成、失败等)、红绿灯
例子
比如超级玛丽,就可能同时有好几个状态比如 跳跃,移动,射击,蹲下 等,如果对这些动作一个个进行处理判断,需要多个if-else或者switch不仅丑陋不说,而且在遇到有组合动作的时候,实现就会变的更为复杂,这里可以使用状态模式来实现。
状态模式的思路是:首先创建一个状态对象或者数组,内部保存状态变量,然后内部封装好每种动作对应的状态,然后状态对象返回一个接口对象,它可以对内部的状态修改或者调用。
红绿灯
定义环境类(红绿灯对象)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30var trafficLight = (function () {
var currentLight = null;
return {
change: function (light) {
currentLight = light;
currentLight.go();
}
}
})();
定义状态类(三种不同颜色的灯)
// 红灯
function RedLight() { }
RedLight.prototype.go = function () {
console.log("this is red light");
}
// 绿灯
function GreenLight() { }
GreenLight.prototype.go = function () {
console.log("this is green light");
}
// 黄灯
function YellowLight() { }
YellowLight.prototype.go = function () {
console.log("this is yellow light");
}
trafficLight.change(new RedLight()); // this is red light
trafficLight.change(new YellowLight()); // this is yellow light
菜单组件
1 | function Menu() { } |
这段代码实例化了一个Menu对象,然后分别切换了显示和隐藏两种状态,如果有第三种状态,我们只需要menuStates添加相应的状态和处理程序即可。
超级玛丽动作
1 | const SuperMarry = (function() { |
这里可以使用ES6的class优化一下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class SuperMarry {
constructor() {
this._currentState = []
this.states = {
jump() {console.log('跳跃!')},
move() {console.log('移动!')},
shoot() {console.log('射击!')},
squat() {console.log('蹲下!')}
}
}
change(arr) { // 更改当前动作
this._currentState = arr
return this
}
go() {
console.log('触发动作')
this._currentState.forEach(T => this.states[T] && this.states[T]())
return this
}
}
new SuperMarry()
.change(['jump', 'shoot'])
.go() // 触发动作 跳跃! 射击!
.go() // 触发动作 跳跃! 射击!
.change(['squat'])
.go() // 触发动作 蹲下!
总结
状态模式的使用场景也特别明确,有如下两点:
一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
一个操作中含有大量的分支语句,而且这些分支语句依赖于该对象的状态。状态通常为一个或多个枚举常量的表示。
简而言之,当遇到很多同级if-else或者switch的时候,可以使用状态模式来进行简化。