状态机模式

状态机模式通常包括以下几个核心模块:

  1. 状态(State)

    • 状态机中的每个状态表示系统在某个时刻的状态。
    • 每个状态可能具有特定的行为和属性。
    • 通常用类或枚举来表示状态。
  2. 事件(Event)

    • 事件是状态之间的转换触发器。
    • 事件可以是用户的输入、系统的内部信号、定时器触发等。
    • 通常用类或枚举来表示事件。
  3. 状态转换(Transition)

    • 状态转换定义了从一个状态到另一个状态的路径,通常由特定的事件触发。
    • 状态转换可以包含条件判断,只有在条件满足时才执行转换。
    • 状态转换还可以包括在转换过程中执行的动作(如进入或退出状态时的行为)。
  4. 状态机(State Machine)

    • 状态机是状态和转换的集合,管理状态之间的转换逻辑。
    • 状态机通常包含当前状态、所有可能的状态、所有可能的事件,以及状态转换表。
    • 状态机负责根据当前状态和事件决定下一步的状态,并执行相应的转换动作。
  5. 动作(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)需要处理多个状态(如身体状态和装备状态),这些状态之间可能存在平行关系,那么可以考虑使用状态机来管理每个状态。每个状态机可以独立地管理其对应状态的转换和行为。

在面向对象的设计中,可以这样理解:

  1. Player 类: Player 类本身不需要直接拥有多个状态机,而是可以持有多个状态对象的指针或引用,每个状态对象可以有自己的状态机。这些状态对象可以是不同类的实例,各自管理自己的状态转换和行为。

  2. 状态对象: 每个状态对象可以包含一个状态机,用于管理该状态的内部状态转换和处理输入。比如,BodyState 类和 EquipmentState 类可以分别管理身体状态和装备状态的转换和行为。

  3. 处理输入: 在 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);
    }

    // 其他方法和数据成员
};

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值