当一个对象的内部状态改变时,会导致其行为的改变,就叫做状态模式。
比如电灯在开和关这两种不同的状态下,点击同一个按钮,得到的反馈是截然不同的。
状态模式解决了方法中大量堆砌 if/else 语句的问题,比如上面提到的电灯,如果用以往的方法去实现:
例子:
const ElectricLight = (state) => { if (state === 'on') { document.body.innerHTML = '打开'; console.log('on'); } else if (state === 'off') { document.body.innerHTML = '关闭'; console.log('off'); } }; // 测试代码 setTimeout(() => { ElectricLight('on'); }, 0); //输出: on setTimeout(() => { ElectricLight('off'); }, 2000); //输出: off
如果电灯的状态并非只有两种,而是还有打开日光、打开强光等,那么就要不断堆砌条件语句。
很显然,这样的实现方式并不理想,此时可以引入状态模式来重构代码:
例子:
const ElectricLight = (() => { // 可用的状态保存在内部(闭包) const state = { on() { document.body.innerHTML = '打开'; console.log('on'); }, off() { document.body.innerHTML = '关闭'; console.log('off'); }, }; // 匹配到 state 中的某一种状态,并执行 const Active = (type) => { state[type](); }; return { Active, }; })(); // 测试代码 setTimeout(() => { ElectricLight.Active('on'); }, 0); //输出: on setTimeout(() => { ElectricLight.Active('off'); }, 2000); //输出: off
重构后的代码,不再有堆砌的条件判断语句,而是通过内部状态的改变,来触发不同的处理方法。
除此之外,很多时候,我们需要管理内部状态,比如这个电灯的例子,默认是关闭,当点击开关按钮时,应该是打开,再次点击时,应该还是关闭,如此往复。
所以,我们可以提供一个内部变量去管理这个状态。
例子:
const ElectricLight = (() => { // 内部变量,用于记住内部状态 let curState = null; const state = { on() { document.body.innerHTML = '打开'; console.log('on'); // 自动将内部状态更新为 off curState = state['off']; }, off() { document.body.innerHTML = '关闭'; console.log('off'); // 自动将内部状态更新为 on curState = state['on']; }, }; const Init = (type) => { // 初始化内部状态 curState = state[type]; }; const Active = () => { if (typeof curState === 'function') { curState(); } }; return { Init, Active, }; })(); //测试代码; ElectricLight.Init('off'); setTimeout(() => { ElectricLight.Active(); }, 0); //输出: on setTimeout(() => { ElectricLight.Active(); }, 2000); //输出: off
完善后的状态模式,状态与状态对应的方法是规定好的,状态之间的切换规则也是规定好的,这才是状态模式的作用所在。
如有错误,欢迎指正,本人不胜感激。