「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」
介绍
很多公司都要求尽可能的减少if-else这些条件分支语句,或许你就会用到状态模式,本期会跟大家聊聊状态模式的那些事,它也许是解决某些需求场景的最好方法,会给你的业务逻辑带来巨大的好处。如果了解游戏开发游戏的小伙伴,在开发游戏人物状态的时候,往往会用到有限状态机,它就是一种状态模式的案例。
举个生活中的栗子,我们小时候在炎热的夏天有种老式的风扇,有三个档,第一次按就会开启风扇的一档,再按就会从一档升到二挡,再按就是二挡升到三挡,到了三挡再按就变成关闭风扇了。如果我们用代码写这个风扇的逻辑,会频繁的使用if-else这些条件分支语句,随着条件的增多,我们维护和查阅的难度会越来越大,接下来,我们会在案例当中来通过状态模式来解决这个问题。
概念
状态模式是一种行为型模式。它解决了对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。
案例
var FSM = {
off:{
name:"关闭",
action:function(){
console.log("触发按钮了,当前状态由"+this.currState.name+"进行改变为一级风");
},
change:function(){
this.currState = this.state.lv1;
return '开启一级风速'
}
},
lv1:{
name:"开启一级风速",
action:function(){
console.log("触发按钮了,当前状态由"+this.currState.name+"进行改变为二级风");
},
change:function(){
this.currState = this.state.lv2;
return '开启二级风速'
}
},
lv2:{
name:"开启二级风速",
action:function(){
console.log("触发按钮了,当前状态由"+this.currState.name+"进行改变为三级风");
},
change:function(){
this.currState = this.state.lv3;
return '开启三级风速'
}
},
lv3:{
name:"开启三级风速",
action:function(){
console.log("触发按钮了,当前状态由"+this.currState.name+"进行改变为关闭");
},
change:function(){
this.currState = this.state.off;
return '关闭'
}
}
}
var delegate = function(client,delegation){
return {
name: delegation.name,
change:function(){
return delegation.change.apply(client,arguments);
},
action:function(){
return delegation.action.apply(client,arguments);
}
}
}
var Fan = function(){
this.state = {
off:delegate(this,FSM.off),
lv1:delegate(this,FSM.lv1),
lv2:delegate(this,FSM.lv2),
lv3:delegate(this,FSM.lv3)
}
this.currState = this.state.off;
}
Fan.prototype.setCurrState = function(stateName){
this.currState = this.state[stateName] || this.state.off;
return this;
}
Fan.prototype.init = function(){
var btn = document.createElement("button");
var msg = document.createElement("span");
msg.style.marginLeft = "15px";
btn.innerHTML = "风扇按钮";
msg.innerHTML = "状态:"+ this.currState.name;
btn.addEventListener("click",function(e){
this.currState.action.apply(this);
var ret = this.currState.change.apply(this);
msg.innerHTML = "状态:"+ret;
}.bind(this),false);
document.body.appendChild(btn);
document.body.appendChild(msg);
}
复制代码
这里我们在一个FSM对象里写了几种状态,其中包含了状态名,行为,以及改变的新的状态。
为了方便通过delegate让他们统一管理他们。
Fan类的state就是相应给予的状态种类,setCurrState可以直接设置状态。而init作为初始化,为了方便我们直接在js当中创建dom。
然后,我们实例化一下Fan类,初始设置为关闭状态。
var fan = new Fan();
fan.setCurrState("off").init();
复制代码
接下来就是见证奇迹的时刻了~
这样,我们就可以通过它去代替丑陋的if-else,以后加多少种状态都会一目了然。
扫描二维码关注公众号,回复:
13681206 查看本文章
优点
- 封装了转换规则,使之更清晰,而且允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块,可维护性增加。
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的数目。
缺点
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景
- 行为随状态改变而改变的场景
- 代替条件分支语句的逻辑。
结语
状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。它可以使你的很多杂乱无章的代码会变得清晰。