咖啡机状态切换机制
用状态模式改造咖啡机的状态管理
问题
咖啡机有多个状态:空闲、加水、加热、冲泡、完成。传统实现用大量 if-else 判断当前状态,代码难以维护。请用状态模式改造状态切换机制。
解答
原始实现(问题代码)
class CoffeeMachine {
constructor() {
this.state = 'idle'
}
action(command) {
// 大量 if-else,难以维护
if (this.state === 'idle') {
if (command === 'addWater') {
this.state = 'filling'
console.log('开始加水')
}
} else if (this.state === 'filling') {
if (command === 'heat') {
this.state = 'heating'
console.log('开始加热')
}
} else if (this.state === 'heating') {
if (command === 'brew') {
this.state = 'brewing'
console.log('开始冲泡')
}
}
// ... 更多状态判断
}
}
状态模式改造
// 状态基类
class State {
constructor(machine) {
this.machine = machine
}
addWater() {
console.log('当前状态无法执行此操作')
}
heat() {
console.log('当前状态无法执行此操作')
}
brew() {
console.log('当前状态无法执行此操作')
}
take() {
console.log('当前状态无法执行此操作')
}
}
// 空闲状态
class IdleState extends State {
addWater() {
console.log('开始加水...')
this.machine.setState(this.machine.fillingState)
}
}
// 加水状态
class FillingState extends State {
heat() {
console.log('水已加满,开始加热...')
this.machine.setState(this.machine.heatingState)
}
}
// 加热状态
class HeatingState extends State {
brew() {
console.log('水已加热,开始冲泡...')
this.machine.setState(this.machine.brewingState)
}
}
// 冲泡状态
class BrewingState extends State {
constructor(machine) {
super(machine)
}
// 冲泡完成自动转换到完成状态
complete() {
console.log('冲泡完成!')
this.machine.setState(this.machine.readyState)
}
}
// 完成状态
class ReadyState extends State {
take() {
console.log('取走咖啡,机器恢复空闲')
this.machine.setState(this.machine.idleState)
}
}
// 咖啡机
class CoffeeMachine {
constructor() {
// 初始化所有状态
this.idleState = new IdleState(this)
this.fillingState = new FillingState(this)
this.heatingState = new HeatingState(this)
this.brewingState = new BrewingState(this)
this.readyState = new ReadyState(this)
// 初始状态为空闲
this.currentState = this.idleState
}
setState(state) {
this.currentState = state
}
getStateName() {
const stateMap = {
[this.idleState]: 'idle',
[this.fillingState]: 'filling',
[this.heatingState]: 'heating',
[this.brewingState]: 'brewing',
[this.readyState]: 'ready'
}
return stateMap[this.currentState]
}
// 委托给当前状态处理
addWater() {
this.currentState.addWater()
}
heat() {
this.currentState.heat()
}
brew() {
this.currentState.brew()
}
take() {
this.currentState.take()
}
}
// 使用示例
const machine = new CoffeeMachine()
machine.addWater() // 开始加水...
machine.heat() // 水已加满,开始加热...
machine.brew() // 水已加热,开始冲泡...
machine.brewingState.complete() // 冲泡完成!
machine.take() // 取走咖啡,机器恢复空闲
// 测试非法操作
machine.brew() // 当前状态无法执行此操作
简化版:用对象映射实现
const createCoffeeMachine = () => {
// 状态转换表
const transitions = {
idle: { addWater: 'filling' },
filling: { heat: 'heating' },
heating: { brew: 'brewing' },
brewing: { complete: 'ready' },
ready: { take: 'idle' }
}
// 状态动作
const actions = {
addWater: () => console.log('开始加水...'),
heat: () => console.log('开始加热...'),
brew: () => console.log('开始冲泡...'),
complete: () => console.log('冲泡完成!'),
take: () => console.log('取走咖啡')
}
let state = 'idle'
return {
getState: () => state,
dispatch(action) {
const nextState = transitions[state]?.[action]
if (nextState) {
actions[action]?.()
state = nextState
return true
}
console.log(`状态 ${state} 下无法执行 ${action}`)
return false
}
}
}
// 使用
const machine = createCoffeeMachine()
machine.dispatch('addWater') // 开始加水...
machine.dispatch('heat') // 开始加热...
machine.dispatch('brew') // 开始冲泡...
machine.dispatch('complete') // 冲泡完成!
machine.dispatch('take') // 取走咖啡
console.log(machine.getState()) // idle
关键点
- 状态模式:将每个状态封装成独立的类,状态自己决定如何响应操作
- 消除 if-else:通过多态替代条件判断,新增状态只需添加新类
- 状态转换表:用对象映射定义合法的状态转换,简洁且易于维护
- 单一职责:每个状态类只关心自己的行为,咖啡机类只负责委托
- 开闭原则:扩展新状态不需要修改现有代码
目录