状态机模式通常包括以下几个核心模块:
-
状态(State):
- 状态机中的每个状态表示系统在某个时刻的状态。
- 每个状态可能具有特定的行为和属性。
- 通常用类或枚举来表示状态。
-
事件(Event):
- 事件是状态之间的转换触发器。
- 事件可以是用户的输入、系统的内部信号、定时器触发等。
- 通常用类或枚举来表示事件。
-
状态转换(Transition):
- 状态转换定义了从一个状态到另一个状态的路径,通常由特定的事件触发。
- 状态转换可以包含条件判断,只有在条件满足时才执行转换。
- 状态转换还可以包括在转换过程中执行的动作(如进入或退出状态时的行为)。
-
状态机(State Machine):
- 状态机是状态和转换的集合,管理状态之间的转换逻辑。
- 状态机通常包含当前状态、所有可能的状态、所有可能的事件,以及状态转换表。
- 状态机负责根据当前状态和事件决定下一步的状态,并执行相应的转换动作。
-
动作(Action):
- 动作是在状态进入、状态退出或状态转换时执行的操作。
- 动作可以是改变系统内部数据、触发其他事件、调用外部服务等。
- 通常通过回调函数或方法来实现动作。
enum Event {
START = 'START',
STOP = 'STOP',
RESET = 'RESET'
}
abstract class BaseState {
protected name: string;
constructor(name: string) {
this.name = name;
}
public getName() {
return this.name;
}
public abstract enter(): void;
public abstract exit(): void;
}
class IdleState extends BaseState {
constructor() {
super('IDLE');
}
public enter() {
console.log('Entering IDLE state...');
}
public exit() {
console.log('Exiting IDLE state...');
}
}
class RunningState extends BaseState {
constructor() {
super('RUNNING');
}
public enter() {
console.log('Entering RUNNING state...');
}
public exit() {
console.log('Exiting RUNNING state...');
}
}
class StoppedState extends BaseState {
constructor() {
super('STOPPED');
}
public enter() {
console.log('Entering STOPPED state...');
}
public exit() {
console.log('Exiting STOPPED state...');
}
}
type Transition = {
from: BaseState;
event: Event;
to: BaseState;
action?: () => void;
}
class StateMachine {
private currentState: BaseState;
private states: Map<string, BaseState>;
private transitions: Transition[];
constructor(initialState: BaseState, transitions: Transition[]) {
this.currentState = initialState;
this.states = new Map();
this.states.set(initialState.getName(), initialState);
this.transitions = transitions;
}
public addState(state: BaseState) {
this.states.set(state.getName(), state);
}
public handleEvent(event: Event) {
const transition = this.transitions.find(t => t.from === this.currentState && t.event === event);
if (transition) {
// 退出当前状态
this.currentState.exit();
// 执行状态转换动作
if (transition.action) {
transition.action();
}
// 更新当前状态
this.currentState = this.states.get(transition.to.getName())!;
// 进入新状态
this.currentState.enter();
} else {
console.log(`No transition for state ${this.currentState.getName()} with event ${event}`);
}
}
public getCurrentState() {
return this.currentState;
}
}
// 定义状态转换和对应的动作
const idleState = new IdleState();
const runningState = new RunningState();
const stoppedState = new StoppedState();
const transitions: Transition[] = [
{
from: idleState,
event: Event.START,
to: runningState,
action: () => console.log('Starting...')
},
{
from: runningState,
event: Event.STOP,
to: stoppedState,
action: () => console.log('Stopping...')
},
{
from: stoppedState,
event: Event.RESET,
to: idleState,
action: () => console.log('Resetting...')
}
];
// 添加状态到状态机
const stateMachine = new StateMachine(idleState, transitions);
// 示例使用
stateMachine.handleEvent(Event.START); // 输出 "Entering RUNNING state..." followed by "Starting..."
stateMachine.handleEvent(Event.STOP); // 输出 "Exiting RUNNING state..." followed by "Entering STOPPED state..." and "Stopping..."
stateMachine.handleEvent(Event.RESET); // 输出 "Exiting STOPPED state..." followed by "Entering IDLE state..." and "Resetting..."
如果一个玩家(Player)需要处理多个状态(如身体状态和装备状态),这些状态之间可能存在平行关系,那么可以考虑使用状态机来管理每个状态。每个状态机可以独立地管理其对应状态的转换和行为。
在面向对象的设计中,可以这样理解:
-
Player 类: Player 类本身不需要直接拥有多个状态机,而是可以持有多个状态对象的指针或引用,每个状态对象可以有自己的状态机。这些状态对象可以是不同类的实例,各自管理自己的状态转换和行为。
-
状态对象: 每个状态对象可以包含一个状态机,用于管理该状态的内部状态转换和处理输入。比如,
BodyState
类和EquipmentState
类可以分别管理身体状态和装备状态的转换和行为。 -
处理输入: 在 Player 类的
handleInput
方法中,可以依次调用每个状态对象的handleInput
方法来处理输入,让每个状态对象自行处理与其相关的输入和状态转换逻辑。
下面是一个简单的示例,演示了如何使用多个状态对象来管理不同状态:
// 假设有一个通用的状态基类
class State {
public:
virtual void handleInput(Player& player, const Input& input) = 0;
// 其他方法和数据成员
};
// 身体状态类
class BodyState : public State {
public:
virtual void handleInput(Player& player, const Input& input) override {
// 处理身体状态的输入和转换逻辑
}
// 其他方法和数据成员
};
// 装备状态类
class EquipmentState : public State {
public:
virtual void handleInput(Player& player, const Input& input) override {
// 处理装备状态的输入和转换逻辑
}
// 其他方法和数据成员
};
// Player 类
class Player {
private:
State* m_bodyState; // 身体状态
State* m_equipmentState; // 装备状态
// 其他数据成员
public:
Player() {
m_bodyState = new BodyState(); // 初始化身体状态
m_equipmentState = new EquipmentState(); // 初始化装备状态
}
~Player() {
delete m_bodyState;
delete m_equipmentState;
}
void handleInput(const Input& input) {
m_bodyState->handleInput(*this, input);
m_equipmentState->handleInput(*this, input);
}
// 其他方法和数据成员
};