咖啡机状态管理
用状态机模式实现咖啡机的状态流转
问题
设计一个咖啡机类,实现以下功能:
- 咖啡机有多个状态:空闲、加水、加咖啡豆、冲泡、完成
- 状态之间有明确的流转规则
- 非法的状态转换要给出提示
解答
基础版:使用状态机模式
class CoffeeMachine {
// 定义所有状态
static STATES = {
IDLE: 'idle', // 空闲
WATER_ADDED: 'water', // 已加水
BEANS_ADDED: 'beans', // 已加咖啡豆
BREWING: 'brewing', // 冲泡中
DONE: 'done' // 完成
}
// 定义状态转换规则
static TRANSITIONS = {
idle: ['water'],
water: ['beans'],
beans: ['brewing'],
brewing: ['done'],
done: ['idle']
}
constructor() {
this.state = CoffeeMachine.STATES.IDLE
}
// 检查是否可以转换到目标状态
canTransitionTo(nextState) {
const allowedStates = CoffeeMachine.TRANSITIONS[this.state]
return allowedStates.includes(nextState)
}
// 执行状态转换
transitionTo(nextState) {
if (!this.canTransitionTo(nextState)) {
console.log(`无法从 ${this.state} 转换到 ${nextState}`)
return false
}
this.state = nextState
console.log(`状态变更为: ${this.state}`)
return true
}
// 加水
addWater() {
return this.transitionTo(CoffeeMachine.STATES.WATER_ADDED)
}
// 加咖啡豆
addBeans() {
return this.transitionTo(CoffeeMachine.STATES.BEANS_ADDED)
}
// 开始冲泡
brew() {
return this.transitionTo(CoffeeMachine.STATES.BREWING)
}
// 完成
finish() {
return this.transitionTo(CoffeeMachine.STATES.DONE)
}
// 重置
reset() {
return this.transitionTo(CoffeeMachine.STATES.IDLE)
}
}
// 测试
const machine = new CoffeeMachine()
machine.addWater() // 状态变更为: water
machine.addBeans() // 状态变更为: beans
machine.brew() // 状态变更为: brewing
machine.addWater() // 无法从 brewing 转换到 water
machine.finish() // 状态变更为: done
machine.reset() // 状态变更为: idle
进阶版:支持异步操作和事件监听
class CoffeeMachine {
static STATES = {
IDLE: 'idle',
WATER_ADDED: 'water',
BEANS_ADDED: 'beans',
BREWING: 'brewing',
DONE: 'done'
}
static TRANSITIONS = {
idle: ['water'],
water: ['beans'],
beans: ['brewing'],
brewing: ['done'],
done: ['idle']
}
constructor() {
this.state = CoffeeMachine.STATES.IDLE
this.listeners = new Map()
}
// 订阅状态变化
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, [])
}
this.listeners.get(event).push(callback)
return () => this.off(event, callback) // 返回取消订阅函数
}
// 取消订阅
off(event, callback) {
const callbacks = this.listeners.get(event)
if (callbacks) {
const index = callbacks.indexOf(callback)
if (index > -1) callbacks.splice(index, 1)
}
}
// 触发事件
emit(event, data) {
const callbacks = this.listeners.get(event) || []
callbacks.forEach(cb => cb(data))
}
// 状态转换
async transitionTo(nextState) {
if (!CoffeeMachine.TRANSITIONS[this.state]?.includes(nextState)) {
throw new Error(`无法从 ${this.state} 转换到 ${nextState}`)
}
const prevState = this.state
this.state = nextState
this.emit('stateChange', { from: prevState, to: nextState })
return this.state
}
// 模拟冲泡过程(异步)
async brew() {
await this.transitionTo(CoffeeMachine.STATES.BREWING)
// 模拟冲泡耗时
await new Promise(resolve => setTimeout(resolve, 2000))
await this.transitionTo(CoffeeMachine.STATES.DONE)
this.emit('coffeeReady')
}
async addWater() {
return this.transitionTo(CoffeeMachine.STATES.WATER_ADDED)
}
async addBeans() {
return this.transitionTo(CoffeeMachine.STATES.BEANS_ADDED)
}
async reset() {
return this.transitionTo(CoffeeMachine.STATES.IDLE)
}
}
// 测试
async function test() {
const machine = new CoffeeMachine()
// 监听状态变化
machine.on('stateChange', ({ from, to }) => {
console.log(`状态: ${from} -> ${to}`)
})
machine.on('coffeeReady', () => {
console.log('☕ 咖啡好了!')
})
await machine.addWater()
await machine.addBeans()
await machine.brew()
await machine.reset()
}
test()
关键点
- 状态机模式:用配置对象定义状态和转换规则,而非硬编码 if-else
- 单向流转:状态只能按预定路径转换,防止非法操作
- 事件驱动:通过发布订阅模式解耦状态变化和业务逻辑
- 异步支持:真实场景中状态转换往往是异步的,需要用 Promise 处理
- 可扩展性:新增状态只需修改配置,不改动核心逻辑
目录