目录
状态模式的一个模型——有限状态机 Finite-state machine
状态模式的定义
状态模式:当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。
类型:对象行为型模式
用途:解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
使用场景:
- 一个由一个或多个动态变化的属性导致发生不同行为的对象,在与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化,那么这个对象,就是有状态的对象
- 代码中包含大量与对象状态有关的条件语句,像是if else或switch case语句,且这些条件执行与否依赖于该对象的状态。
优点:
- 一个状态状态对应行为,封装在一个类里,更直观清晰,增改方便
- 状态与状态间,行为与行为间彼此独立互不干扰
- 避免事物对象本身不断膨胀,条件判断语句过多
- 每次执行动作不用走很多不必要的判断语句,用哪个拿哪个
缺点:
- 需要将事物的不同状态以及对应的行为拆分出来,有时候会无法避免的拆分的很细,有的时候涉及业务逻辑,一个动作拆分出对应的两个状态,动作就拆不明白了,过度设计
- 必然会增加事物类和动作类的个数,有时候动作类再根据单一原则,按照功能拆成几个类,会反而使得代码混乱,可读性降低
状态模式的一个模型——有限状态机 Finite-state machine
日常开发中很多具有多种状态的对象,都可以用有限状态机模型来模拟,一般都具有以下特点:
- 事物拥有多种状态,任一时间只会处于一种状态不会处于多种状态;
- 动作可以改变事物状态,一个动作可以通过条件判断,改变事物到不同的状态,但是不能同时指向多个状态,一个时间,就一个状态
- 状态总数是有限的;
github上有一个有限状态机的函数库javascript-state-machine,可以了解一下
https://github.com/jakesgordon/javascript-state-machine
演示范例1 —— 状态模式实现对话框的显示和隐藏
var Dialog = function(){
var _state = null;
this.setState = function(state){
_state = state;
}
this.getState = function(){
return _state;
}
}
var ShowState = function(){
this.doAction = function(dialog){
console.log("对Dialog设置显示状态:");
dialog.setState(this);
}
this.toString = function(){
console.log("显示中......");
}
}
var HideState = function(){
this.doAction = function(dialog){
console.log("对Dialog设置隐藏状态:");
dialog.setState(this);
}
this.toString = function(){
console.log("已隐藏......");
}
}
var dialog = new Dialog();
var showState = new ShowState();
var hideState = new HideState();
showState.doAction(dialog);
//对Dialog设置显示状态:
dialog.getState().toString();
//显示中......
hideState.doAction(dialog);
//对Dialog设置隐藏状态
dialog.getState().toString();
//已隐藏......
例子里Dialog对象有两种状态,显示和隐藏,我把两种状态提取出来,使得状态的管理更加灵活。在这个例子里面Dialog称之为环境类,环境类又称为上下文类,他拥有多种状态。环境类内部需要维护一个state对象用来定义当前状态。HideState,ShowState称之为状态类,对应环境类的一个具体状态,toString称之为状态类的行为,每一个状态类的行为都有所不同。
演示范例2 —— 状态模式实现角色扮演游戏(如魂斗罗)
class Contra {
constructor () {
//存储当前待执行的动作 们
this._currentstate = {};
}
//添加动作
changeState (){
//清空当前的动作集合
this._currentstate = {};
//遍历添加动作
Object.keys(arguments).forEach(
(i) => this._currentstate[arguments[i]] = true
)
return this;
}
//执行动作
contraGo (){
//当前动作集合中的动作依次执行
Object.keys(this._currentstate).forEach(
(k) => Actions[k] && Actions[k].apply(this)
)
return this;
}
};
const Actions = {
up : function(){
//向上跳
console.log('up');
},
down : function(){
//趴下
console.log('down');
},
forward : function(){
//向前跑
console.log('forward');
},
backward : function(){
//往老家跑
console.log('backward');
},
shoot : function(){
//开枪吧
console.log('shoot');
},
};
var littlered = new Contra();
littlered.changeState('shoot','up').contraGo();
控制台会输出: shoot up
状态模式,将条件判断的结果转化为状态对象内部的状态(代码中的up,down,backward,forward),内部状态通常作为状态对象内部的私有变量(this._currentState),然后提供一个能够调用状态对象内部状态的接口方法对象(changeState,contraGo),这样对状态的改变,对状态方法的调用的修改和增加也会很容易,方便了对状态对象中内部状态的管理。
同时,状态模式将每一个条件分支放入一个独立的类中,也就是代码中的Actions。这使得你可以根据对象自身的情况将对象的状态(动作——up,down,backward,forward)作为一个对象(Actions.up,Actions.down这样),这一对象可以不依赖于其他对象而独立变化(一个行为一个动作,互不干扰)。
可以看出,状态模式就是一种适合多种状态场景下的设计模式,改写之后代码更加清晰,提高代码的维护性和扩展性,不用再牵一发动全身
演示范例3 —— 状态模式实现红绿灯
var 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());
trafficLight.change(new YellowLight());
trafficLight是一个红绿灯的实例,传入一个构造函数,对象暴露change方法改变内部状态,也就是灯的颜色,change接收的同样是一个状态的对象,调用对象的方法触发响应的动作,这里的动作都叫go,不同颜色的灯对象有着不同的go的实现。
通过传入灯对象到change方法中,从而改变红绿灯的状态,触发其相应的处理程序,这就是一个典型的状态模式的应用。
更多设计模式详见——js设计模式【详解】总目录
https://blog.csdn.net/weixin_41192489/article/details/116154815