# 设计模式:状态模式

# 什么是状态模式

某个对象, 当切换到不同的状态时那么他对应的行为也是不一样的

# 使用场景

智能灯: 它的功能有开灯, 弱光, 强光, 关灯. 那么这四种状态对应的光的强弱和开关就是典型的状态模式的应用场景

# Coding

智能灯

原始的写法
var Light = function() {
  this.state = 'off' // 初始状态
  this.button = null // 点灯的开关按钮
}

Light.prototype.init = function() {
  var button = document.createElement('button')
  var self = this;

  button.innerHTML = '开关'
  this.button = document.body.appendChild(button)
  this.button.onclick = function() {
    self.buttonWasPreseed()
  }
}

Light.prototype.buttonWasPreseed = function() {
  if (this.state === 'off') {
    this.state = 'weakLight'
    console.log('弱光')
  } else if (this.state === 'weakLight') {
    this.state = 'on'
    console.log('强光')
  } else if (this.state === 'on') {
    this.state = 'off'
    console.log('关灯')
  }
}
var light = new Light();
light.init()

我们看到在状态判断的地方充斥着大量的条件分支语句, 这样是很糟糕的代码。

优化后的样子
var Light = function() {
  this.offState = delegate(this, FSM.off)
  this.onState = delegate(this, FSM.on)
  this.currentState = this.offState
  this.button = null
}
Light.prototype.init = function() {
  var button = document.createElement('button');
  var self = this;
  button.innerHTML = '已关灯';
  this.button = document.body.appendChild(button);
  this.button.onclick = function() {
    self.currentState.buttonWasPressed.call(self);
  }
}

var delegate = function(client, delegation) {
  return {
    buttonWasPressed: function() {
      return delegation.buttonWasPressed.apply(client, arguments);
    }
  }
}

var FSM = {
  off: {
    buttonWasPressed: function() {
      console.log('关灯')
      this.button.innerHTML = '开灯'
      this.currentState = FSM.on
    }
  },
  on: {
    buttonWasPressed: function() {
      console.log('开灯')
      this.button.innerHTML = '关灯'
      this.currentState = FSM.off
    }
  }
}
new Light().init()

我们用一个状态机来定义每个状态对应的行为,用 delegate 来委托状态和对象之间的关系。这样我们并不需要事先让一个对象持有另一个对象而是通过 Function.prototype.call 的方法更改了 this 指向。

# 总结

在实际开发中还是有很多场景可以用到状态模式的,比如某些复杂的表格要根据用户角色来提供不同的字段。比如订单对象的各个阶段(加入购物车,付款,发货,收货,评价)等等,大量的业务场景如果用状态模式来重构这样的代码逻辑一定会更加清晰,更加容易维护。

上次更新: 10/19/2020, 6:24:06 PM