您的当前位置:首页[因为我不懂啊]-什么是状态机编程(设计模式)(1)

[因为我不懂啊]-什么是状态机编程(设计模式)(1)

2024-12-14 来源:哗拓教育

本阶段对状态机编程的理解:

  • 把物体的操作逻辑分为几个状态,每个状态有对应的处理
  • 操作时,只需要去改变物体状态即可,物体会自动根据状态执行对应的处理

这段理解放入示例中是这样的:

  • 电梯有四个状态:开门、关门、运动、停止
  • 电梯在达到某个状态时,会输出对应的log作为处理
  • 电梯对外有一个goto指定楼层的接口

下面来详细设计一下相关的内容

  • 状态[枚举]
    - 开门
    - 关门
    - 运动
    - 静止

  • 电梯[类]
    - 状态标志[变量]
    - 设置状态[方法]
    - 开门的处理[方法]
    - 关门的处理[方法]
    - 运动的处理[方法]
    - 停止的处理[方法]

    - 移动到楼层[方法]
    - 当前楼层[变量]
    - 目标楼层[变量]
    

实现代码:

//
//  ElevatorOne.hpp
//  QFLTest
//
//  Created by QuFangliu on 16/9/18.
//
//

/*
    电梯测试_1
 
    运行逻辑:
        停止->开门(进入)->关门->运动->停止->开门(离开)->关门
 
    ????我tm写的什么
 
 
 */

#ifndef ElevatorOne_hpp
#define ElevatorOne_hpp

#include <stdio.h>

enum ElevatorOneState
{
    State_Opening   = 1,    //电梯门打开状态
    State_Closing   = 2,    //电梯门关闭状态
    State_Running   = 3,    //电梯运动状态
    State_Stopping  = 4     //电梯静止状态
};

class ElevatorOne
{
public:
    ElevatorOne();
    virtual ~ElevatorOne();
    
public:
    void gotoFloor(int nFloor);
    
private:
    void setState(ElevatorOneState eState); //只能通过事件来改变电梯的状态,电梯自动运行
    
    void open();    //开门
    void close();   //关门
    void run();     //运动
    void stop();    //减速到停止
    
private:
    ElevatorOneState m_eState;  //电梯状态标志
    int m_nTargetFloor;         //电梯目标楼层
    int m_nFloor;               //电梯所在楼层
};

#endif /* ElevatorOne_hpp */
//
//  ElevatorOne.cpp
//  QFLTest
//
//  Created by QuFangliu on 16/9/18.
//
//

#include "ElevatorOne.hpp"
#include <iostream>

#define QFLLOG(_text_)  do  \
                        {   \
                            std::cout << _text_ << std::endl;   \
                        } while (false) \

ElevatorOne::ElevatorOne()
{
    m_eState = ElevatorOneState::State_Stopping;    //默认静止状态
    m_nFloor = 1;                                   //默认楼层1楼
    m_nTargetFloor = 1;                             //默认目标1楼
}

ElevatorOne::~ElevatorOne()
{
    
}

//操作
void ElevatorOne::gotoFloor(int nFloor)
{
    if (m_nTargetFloor == nFloor) {
        //不需要运动
        QFLLOG("Elevator is here.");
    }
    else {
        //设置目标楼层
        m_nTargetFloor = nFloor;
        //状态转换
        this->setState(ElevatorOneState::State_Opening);
    }
}

//状态转换
void ElevatorOne::setState(ElevatorOneState eState)
{
    m_eState = eState;
    
    switch (eState) {
        case State_Opening:
            this->open();
            break;
        case State_Closing:
            this->close();
            break;
        case State_Running:
            this->run();
            break;
        case State_Stopping:
            this->stop();
            break;
        default:
            break;
    }
}

//运行逻辑
//开门
void ElevatorOne::open()
{
    QFLLOG("Elevator open...");
    
    //下一个状态必然是close
    this->setState(ElevatorOneState::State_Closing);
}
//关门
void ElevatorOne::close()
{
    QFLLOG("Elevator close...");
    
    //根据目标楼层,判断进入怎样的状态
    if (m_nFloor != m_nTargetFloor) {
        this->setState(ElevatorOneState::State_Running);
    }
    else {
        //结束状态
    }
}
//运行
void ElevatorOne::run()
{
    QFLLOG("Elevator run..." << m_nTargetFloor);
    
    //移动到对应的楼层
    m_nFloor = m_nTargetFloor;
    
    //下一个状态必然是stop
    this->setState(ElevatorOneState::State_Stopping);
}
//静止
void ElevatorOne::stop()
{
    QFLLOG("Elevator stop...");
    
    //下一个状态必然是open
    this->setState(ElevatorOneState::State_Opening);
}

上面就是Elevator的完整逻辑代码,运行测试过程代码如下,直接放在 int main(void)中即可,我示例中是写在按钮的触发事件中。

    //elevator
    auto pElevator = new ElevatorOne();
    pElevator->gotoFloor(20);
    pElevator->gotoFloor(20);//移动到本层试试

输出结果:
Elevator open...
Elevator close...
Elevator run...20
Elevator stop...
Elevator open...
Elevator close...
Elevator is here.


总结:
1.我不知道为什么要写一个gotoFloor的函数,只是觉得在测试中直接去写setState会很别扭,不符合正常控制过程(虽然在其他的博客中看到的关于FSM的实例代码,调用时都是直接写了几个setState)。
2.虽然这里有区分4个状态,每个状态也有对应的处理函数。但是我觉得这里使用状态并没有什么用。因为[使用setState转移到下一个状态],都可以直接用[下一个状态的处理函数]来替换。也就是说
//状态转换 this->setState(ElevatorOneState::State_Opening);
可以直接使用
//状态转换 this->open();
来代替。


求懂FSM的小伙伴评论指点。

显示全文