状态机、封装和 OOP 设计

State machines, encapsulation and OOP design

我正在使用 Boost's MSM library 实现 FSM。

在 FSM 中,我有转换表描述 Events,Source states,Target 状态,Actions 和 Guards。

这是我第一次使用状态机的更高层次设计。过去,我只是使用 switch 语句和执行代码。然而,这个会很大,我想把所有东西都组织得井井有条,这样就不会变得一团糟。

我有一个代表状态机的对象(它是一个 boost::msm::back::state_machine<MyStateMachine> where MyStateMachine is my implemenmtation which inherits from boost::msm::front::state_machine_def )。

诀窍是我的业务逻辑将在 Action 中完成。我认为这对于 FSM 来说并不罕见。 Boost's examples 似乎建议这些 Actions 应该作为状态机本身的方法来实现,但我认为这也可能使 class大量的。我觉得把工作和状态机分开是有意义的。

保持可读、可维护和可扩展的设计哪个更有意义?

  1. 在 FSM 的方法中执行业务逻辑 class(我担心这会将状态管理与工作过于紧密地混合在一起)。

  2. 在实例化 FSM 的父级中执行业务逻辑。 FSM 将需要一个指向父级的指针,而父级将需要实现 FSM 理解的接口(或者 FSM 实现将需要#include 父级的声明)。

  3. 在 FSM 实例化并拥有的新 class 中执行业务逻辑。

  4. 在一个新的 class 中执行业务逻辑,它由父级实例化并拥有,但作为引用(或指针)传递给 FSM。

  5. 其他。

这取决于你的情况,但我有一种我通常使用的方法。

可能是 2 或 5 的变体。

假设 your_app 有您的业务逻辑。它需要充当状态机。我认为这是状态机的典型用例之一。

在这种情况下,状态机可以放置为 your_app 的嵌套 class。 your_app有成员变量sm_,状态机实例。

状态机的定义是sm_def。它具有 your_app.

的引用

your_app 之外的人想要处理事件时,请调用 your_app::process_event()。如果不想提供直接的事件处理接口,可以包装成your_app::handle_some()。如果这样做,your_app::process_event() 应该是私有的。

下面是示例实现:

#include <iostream>
#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;


// application domain
class your_app {
public:
    your_app() :sm_(boost::ref(*this)) {
        sm_.start(); // start state machine
    }

    // public interface for event processing

    // Event definitions
    struct Event1 {
        int param;
    };

    template <typename Event>
    void process_event(Event const& ev) {
        sm_.process_event(ev);
    }

    void handle_some(int param) {
        process_event(Event1 {param});
    }
private:

    // internal business logic triggered from the state machine
    void do_some_business(int param) {
        std::cout << "do_some_business " << param << std::endl;
    }

    // state machine definiition
    struct sm_def:msmf::state_machine_def<sm_def> {
        sm_def(your_app& ya):ya_(ya) {}
        // States
        struct State1:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) {
                std::cout << "State1::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) {
                std::cout << "State1::on_exit()" << std::endl;
            }
        };
        struct State2:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) {
                std::cout << "State2::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) {
                std::cout << "State2::on_exit()" << std::endl;
            }
        };

        // Set initial state
        typedef State1 initial_state;

        // Actions
        struct Action {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const& e, Fsm& f, SourceState&, TargetState&) const {    
                // get your_app via Fsm.
                f.ya_.do_some_business(e.param);
            }
        };

        // Transition table
        struct transition_table:mpl::vector<
            //          Start   Event   Next    Action  Guard
            msmf::Row < State1, Event1, State2, Action, msmf::none >,
            msmf::Row < State2, Event1, State1, Action, msmf::none >
        > {};

        your_app& ya_;
    };

    friend class sm; // give the friend access to the sm
    typedef msm::back::state_machine<sm_def> sm;

    sm sm_;
};

int main() {
    your_app ya;

    ya.process_event(your_app::Event1{42});
    ya.handle_some(44);
}

和运行演示:https://wandbox.org/permlink/PQGSGr0bnJHgaMpD