一般写法,使用if判断状态,让状态下移
let Light = function() {
this.state = 'off'
this.button = null
}
let Button = {
name: 'button',
innerHTML: ''
}
Light.prototype.init = function() {
let button = Button
button.innerHTML = '开关'
this.button = button
this.button.click = () => {
this.buttonWasPressed()
}
}
Light.prototype.buttonWasPressed = function() {
if (this.state == 'off') {
this.state = 'on'
} else {
this.state = 'off'
}
}
let light = new Light()
light.init()
console.log('light.state', light.state)
light.button.click()
console.log('light.state', light.state)
Light.prototype.buttonWasPressed = function() {
if (this.state == 'off') {
this.state = 'weakLight'
} else if(this.state == 'weakLight'){
this.state = 'strongLight'
} else if(this.state == 'strongLight'){
this.state = 'off'
}
}
let light = new Light()
light.init()
console.log('light.state', light.state)
light.button.click()
console.log('light.state', light.state)
light.button.click()
console.log('light.state', light.state)
思想:不同即须抽离,低内聚。
分离不同的状态数据独立处理,主体通过切换状态类来控制状态的切换,将状态的切换权移交给状态本身。
let OffLightState = function(light) {
this.light = light
this.msg = 'off' // 存储分散的状态数据,分离状态差异。
}
OffLightState.prototype.buttonWasPressed = function() {
// 预设好下一个状态
this.light.setState(this.light.weakLightState) // 调用主体的方法来设置主体的状态。
}
let WeakLightState = function(light) {
this.light = light
this.msg = 'weak'
}
WeakLightState.prototype.buttonWasPressed = function() {
this.light.setState(this.light.strongLightState)
}
let StrongLightState = function(light) {
this.light = light
this.msg = 'strong'
}
StrongLightState.prototype.buttonWasPressed = function() {
this.light.setState(this.light.offLightState)
}
let Light = function() {
// 本体存储所有状态。
this.offLightState = new OffLightState(this) // 实例化并绑定好每一个状态
this.weakLightState = new WeakLightState(this)
this.strongLightState = new StrongLightState(this)
this.button = null
}
let Button = {
name: 'button',
innerHTML: ''
}
Light.prototype.init = function() {
let button = Button
button.innerHTML = '开关'
this.button = button
this.setState(this.offLightState)
this.button.click = () => {
// 每次按下就改变状态,让状态自己来控制下一个状态是谁。
// 将状态改变的按钮操作分离出去,自己只保留状态设置接口。
// 每次当前状态按下时设置下一个状态,通过状态自身来传递,而不是主体Light。
this.currState.buttonWasPressed()
}
}
Light.prototype.setState = function(newState) {
// 设置当前状态实例。
this.currState = newState
}
let light = new Light()
light.init()
console.log('light.currState', light.currState.msg)
light.button.click()
console.log('light.currState', light.currState.msg)
light.button.click()
console.log('light.currState', light.currState.msg)
新增一个状态改变三个地方,状态类+按钮方法,且增加后倒数第二个需要调整状态顺序,实例
书中针对新增类需要新增方法的遗漏的补充做法是新增一个父类,并要求子类必须重写父类的方法,否则抛错提示。
let OffLightState = function() {
this.msg = 'off'
}
let WeakLightState = function() {
this.msg = 'weak'
}
let StrongLightState = function() {
this.msg = 'strong'
}
let Light = function() {
// 本体存储所有状态。
this.offLightState = new OffLightState() // 实例化并绑定好每一个状态
this.weakLightState = new WeakLightState()
this.strongLightState = new StrongLightState()
this.button = null
}
let Button = {
name: 'button',
innerHTML: ''
}
// 使用yield来控制状态顺序
function *gen() {
while(true) {
yield this.setState(this.weakLightState)
yield this.setState(this.strongLightState)
yield this.setState(this.offLightState)
}
}
Light.prototype.init = function() {
let button = Button
button.innerHTML = '开关'
this.button = button
this.setState(this.offLightState)
let it = gen.call(this)
this.button.click = () => {
it.next()
}
}
Light.prototype.setState = function(newState) {
// 设置当前状态实例。
this.currState = newState
}
let light = new Light()
light.init()
console.log('light.currState', light.currState)
light.button.click()
console.log('light.currState', light.currState)
light.button.click()
console.log('light.currState', light.currState)
减少了新增类需要新增方法的操作及状态顺序的修改
新增一个状态只需改变三个地方,状态类,实例,yield
let Light = function() {
this.currState = FSM.off
this.button = null
}
let Button = {
name: 'button',
msg: ''
}
Light.prototype.init = function() {
let button = Button
this.button = button
this.button.click = () => {
this.currState.buttonWasPressed.call(this) // 行为是外部状态的行为
}
}
// 单独维护一个状态对象及状态对应的行为
let FSM = {
off: {
buttonWasPressed: function() {
this.button.msg = '关灯'
this.currState = FSM.on // 状态是第三方的状态,不是主体的。
}
},
on: {
buttonWasPressed: function() {
this.button.msg = '开灯'
this.currState = FSM.off
}
}
}
let light = new Light()
light.init()
console.log('light.button', light.button.msg)
light.button.click()
console.log('light.button', light.button.msg)
light.button.click()
console.log('light.button', light.button.msg)
上面的例子语义上的缺陷,下面使用委托来处理。
让主体本身也有了状态和行为,但把自己的状态对应的行为委托给了外部的状态对象去处理。
let delegate = function(client, delegation) {
return {
buttonWasPressed: function() {
return delegation.buttonWasPressed.apply(client, arguments)
}
}
}
let Light = function() {
this.offState = delegate(this, FSM.off)
this.onState = delegate(this, FSM.on)
this.currState = this.offState
this.button = null
}
let Button = {
name: 'button',
msg: ''
}
Light.prototype.init = function() {
let button = Button
this.button = button
this.button.click = () => {
this.currState.buttonWasPressed() // 按钮的语义更清晰
}
}
let FSM = {
off: {
buttonWasPressed: function() {
this.button.msg = '关灯'
this.currState = this.onState
}
},
on: {
buttonWasPressed: function() {
this.button.msg = '开灯'
this.currState = this.offState
}
}
}
let light = new Light()
light.init()
console.log('light.button', light.button.msg)
light.button.click()
console.log('light.button', light.button.msg)
light.button.click()
console.log('light.button', light.button.msg)
let delegate = function(client, delegation) {
return {
buttonWasPressed: function() {
return delegation.buttonWasPressed.apply(client, arguments)
}
}
}
let FSM = { // 维护状态对应的行为
off: {
buttonWasPressed: function() {
this.button.msg = '关灯'
}
},
on: {
buttonWasPressed: function() {
this.button.msg = '开灯'
}
}
}
let Button = {
name: 'button',
msg: ''
}
let Light = {
data() {
return {
// 维护内部状态变量
offState: delegate(this, FSM.off),
onState: delegate(this, FSM.on),
currState: '',
button: null,
}
},
init () {
Object.assign(this, this.data())
this.currState = this.offState
let button = Button
this.button = button
let it = this.genState()
this.button.click = () => {
it.next()
this.currState.buttonWasPressed() // 按钮的语义更清晰
}
},
*genState() { // 维护内部状态顺序
while(true) {
yield this.currState = this.offState
yield this.currState = this.onState
}
}
}
Light.init()
console.log('Light.button', Light.button.msg)
Light.button.click()
console.log('Light.button', Light.button.msg)
Light.button.click()
console.log('Light.button', Light.button.msg)
最后的写法新增了yield来改进以往的状态模式,如有新的模式,请与我交流。