js 设计模式——状态模式
程序员文章站
2023-11-09 21:24:22
状态模式 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。 简单的解释一下: 第一部分的意思是将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化。 第二部分是从客户的角度来看,我们使用的对象,在不同的状态下具有截然不同的行为,这个 ......
状态模式
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
简单的解释一下:
- 第一部分的意思是将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化。
- 第二部分是从客户的角度来看,我们使用的对象,在不同的状态下具有截然不同的行为,这个对象看起来是从不同的类中实例化而来的,实际上这是使用了委托的效果。
现在举一个网上比较多的例子,没错就是电灯的例子(不要烦,请耐心往下看)
// 首先定义了一个light类 class light { // 定义一个状态变量 constructor(){ this.state = 'off' } // 定义一个改变状态的方法 change(){ if(this.state === 'off'){ console.log('开灯') this.state = 'on' } else { console.log('关灯') this.state = 'off' } } } // 创建实例 let light = new light() // 调用方法 light.change()
当当当当,到此我们已经编写了一个状态机,逻辑简单又缜密,看起来还有那么点无懈可击。but,你懂的事实并非如此,人生也没那么多的如意。随着人类的进步,需求也不(de) 断(cuo) 进(jin) 步(chi)(●'◡'●),于是新的电灯出现了,这电灯可厉害了,第一次点击弱光,再次点击强光,再点七彩光,再点emmm关了。
按我们上面的逻辑来写,那可就刺激了:
- 首先违反了开闭原则,每次改动都要更改change()方法,使得方法变得不稳定
- 状态切换的不明显,无法一目了然的明白一共有多少种状态
- 状态之间的切换关系,不过是往change()方法里添加if、else语句,是change()方法更加难阅读和维护
那怎么办呢?有首歌怎么唱来着“新的电灯已经出现,怎么能够停滞不前”,哈哈,所以状态模式来了~~~
因为电灯的例子太无聊了,所以我换了一个例子但是呢意思是一样滴:
// 单曲循环类 class singlecycle{ constructor(self){ this._self = self } modeswitch(){ console.log('现在是单曲循环') this._self.setstate( this._self.listcirculation ) } } // 列表循环类 class listcirculation{ constructor(self){ this._self = self } modeswitch(){ console.log('现在是列表循环') this._self.setstate( this._self.sequentialplay ) } } // 顺序播放类 class sequentialplay{ constructor(self){ this._self = self } modeswitch(){ console.log('现在是顺序播放') this._self.setstate( this._self.shuffleplay ) } } // 随机播放类 class shuffleplay{ constructor(self){ this._self = self } modeswitch(){ console.log('现在是随机播放') this._self.setstate( this._self.singlecycle ) } } // 音乐类 class music{ constructor(){ // 为每个状态都创建一个状态对象 this.singlecycle = new singlecycle(this) this.listcirculation = new listcirculation(this) this.sequentialplay = new sequentialplay(this) this.shuffleplay = new shuffleplay(this) // 定义初始状态为顺序播放 this.currstate = this.sequentialplay } // 切换播放模式 changemode(){ this.currstate.modeswitch() } // 下一次点击时的播放状态 setstate(newstate){ this.currstate = newstate; } } // 实例化音乐类 let music = new music() // 调用切换播放模式方法 music.changemode()
好了,到此我们改编完成,如果你没有懵掉,good,如果你懵掉了,往下看:
- 首先我们定义了4个状态类
singlecycle(单曲循环)
、listcirculation(列表循环)
、sequentialplay(顺序播放)
、shuffleplay(随机播放)
- 每个状态类都定义了一个变量
_self
来接收music(音乐类)
传过来的this
,还有一个方法modeswitch(状态更改)
,用来改变下一次要播放的状态 - 然后定义了一个
music(音乐类)
,首先在里面为每一个状态都创建了一个状态对象,还定义了一个变量currstate
来记录下一次点击时的状态。 - 最后就是music(音乐类)里面定义的两种方法
changemode(切换播放模式)
、setstate(下一次点击时的播放状态)
。当我们点击切换模式的时候,在changemode(切换播放模式)
中去调用之前定义好的状态类中的modeswitch(状态更改)
方法,完成模式切换的同时调用music(音乐类)中的setstate(下一次点击时的播放状态)
方法来对状态进行改变,保证下一次点击时切换不同的模式。
通过上面的方法可以看出:
- 我们可以在
music(音乐类)
中清楚的知道一共有多少个状态,同时music(音乐类)
中不再进行任何实质性的操作,而是通过this.currstate.modeswitch()
交给了当前持有的状态对象去执行 - 状态的切换规律被事先在每一个状态类中定义好了,在
music(音乐类)
中没有任何一个和状态切换相关的条件分支语句
悄悄地说,上面的方法还阔以再完美一点呦
小小的拓展
通过上面的介绍我们了解到了每一个状态类都有一个 modeswitch()
方法,也就意味着我们每次添加状态类都要写一个方法,问题来了,人非圣贤,孰能无过?所以咧难免会丢掉的嘛!
然后做一些小小的优化:
// 定义一个state类 class state{ constructor(self){ this._self = self } modeswitch(){ throw new error( '父类的 modeswitch 方法必须被重写' ) } } // 状态类(举一个为例) // 单曲循环类(继承state类) class singlecycle extends state{ modeswitch(){ console.log('现在是单曲循环') this._self.setstate( this._self.listcirculation ) } }
好了完成,当某一天我们忘了写方法,也能够快速的定位到错误
目前对于状态模式的理解就这么多,以后有了新的理解会继续更新的,溜了溜了(~ ̄▽ ̄)~