|
| 1 | +# 状态模式 |
| 2 | + |
| 3 | +> 状态模式允许一个对象在其内部状态改变时改变行为,这个对象看上去像改变了类一样,但其实并没有。状态模式把所研究对象在其内部状态改变时,其行为也随之改变,状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统改变所选的子类。 |
| 4 | + |
| 5 | +假设我们此时有一个电灯,在电灯上有个开关,在灯未亮时按下使灯开启,在灯已亮时按下则将灯关闭,此时行为表现时不一样的: |
| 6 | + |
| 7 | +```javascript |
| 8 | +class Light { |
| 9 | + constructor() { |
| 10 | + this.state = 'off'; //电灯默认为关闭状态 |
| 11 | + this.button = null; |
| 12 | + } |
| 13 | + |
| 14 | + init() { |
| 15 | + let button = document.createElement('button'); |
| 16 | + let self = this; |
| 17 | + button.innerHTML = '我是开关'; |
| 18 | + this.button = document.body.appendChild(button); |
| 19 | + this.button.onclick = () => { |
| 20 | + self.buttonWasClicked(); |
| 21 | + } |
| 22 | + } |
| 23 | + |
| 24 | + buttonWasClicked() { |
| 25 | + if (this.state === 'off') { |
| 26 | + console.log('开灯'); |
| 27 | + this.state = 'on'; |
| 28 | + } else { |
| 29 | + console.log('关灯'); |
| 30 | + this.state = 'off'; |
| 31 | + } |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +let light = new Light(); |
| 36 | +light.init(); |
| 37 | +``` |
| 38 | + |
| 39 | +[](https://imgchr.com/i/uD8U1A) |
| 40 | + |
| 41 | +此时只有两种状态,我们尚且可以不使用状态模式,但当状态较多时,例如,当电灯出现弱光,强光档位时,以上的代码就无法满足需求。 |
| 42 | + |
| 43 | +### ### 使用状态模式重构 |
| 44 | + |
| 45 | +状态模式的关键是把每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部,在按钮被按下时,只需要在上下文中,把这个请求委托给当前状态对象即可,该状态对象会负责渲染它自身的行为。 |
| 46 | + |
| 47 | +首先定义三种不同状态的类 |
| 48 | + |
| 49 | +```javascript |
| 50 | +// 灯未开启的状态 |
| 51 | +class OffLightState { |
| 52 | + constructor(light) { |
| 53 | + this.light = light; |
| 54 | + } |
| 55 | + |
| 56 | + buttonWasClicked() { |
| 57 | + console.log('切换到弱光模式'); |
| 58 | + this.light.setState(this.light.weakLightState); |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +// 弱光状态 |
| 63 | +class WeakLightState { |
| 64 | + constructor(light) { |
| 65 | + this.light = light; |
| 66 | + } |
| 67 | + |
| 68 | + buttonWasClicked() { |
| 69 | + console.log('切换到强光模式'); |
| 70 | + this.light.setState(this.light.strongLightState); |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +// 强光状态 |
| 75 | +class StrongLightState { |
| 76 | + constructor(light) { |
| 77 | + this.light = light; |
| 78 | + } |
| 79 | + |
| 80 | + buttonWasClicked() { |
| 81 | + console.log('关灯'); |
| 82 | + this.light.setState(this.light.offLightState); |
| 83 | + } |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +接着我们改写 Light 类,在内部通过`curState`记录当前状态 |
| 88 | + |
| 89 | +```javascript |
| 90 | +class Light { |
| 91 | + constructor() { |
| 92 | + this.offLightState = new OffLightState(this); |
| 93 | + this.weakLightState = new WeakLightState(this); |
| 94 | + this.strongLightState = new StrongLightState(this); |
| 95 | + this.button = null; |
| 96 | + } |
| 97 | + |
| 98 | + init() { |
| 99 | + let button = document.createElement('button'); |
| 100 | + let self = this; |
| 101 | + button.innerHTML = '我是开关'; |
| 102 | + this.button = document.body.appendChild(button); |
| 103 | + this.curState = this.offLightState; |
| 104 | + this.button.onclick = () => { |
| 105 | + self.curState.buttonWasClicked(); |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + setState(state) { |
| 110 | + this.curState = state; |
| 111 | + } |
| 112 | +} |
| 113 | +``` |
| 114 | + |
| 115 | +之后实例化对象后,我们在页面中查看 |
| 116 | + |
| 117 | +```javascript |
| 118 | +let light = new Light(); |
| 119 | +light.init(); |
| 120 | +``` |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | +[](https://imgchr.com/i/uDGh2d) |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +## 总结 |
| 129 | + |
| 130 | +- 状态模式通过定义不同的状态类,根据状态的改变而改变对象的行为。 |
| 131 | +- 不必把大量的逻辑都写在被操作的对象的类中,很容易增加新的状态。 |
| 132 | +- 符合开放-封闭原则。 |
0 commit comments