状态机、封装和 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大量的。我觉得把工作和状态机分开是有意义的。
保持可读、可维护和可扩展的设计哪个更有意义?
在 FSM 的方法中执行业务逻辑 class(我担心这会将状态管理与工作过于紧密地混合在一起)。
在实例化 FSM 的父级中执行业务逻辑。 FSM 将需要一个指向父级的指针,而父级将需要实现 FSM 理解的接口(或者 FSM 实现将需要#include 父级的声明)。
在 FSM 实例化并拥有的新 class 中执行业务逻辑。
在一个新的 class 中执行业务逻辑,它由父级实例化并拥有,但作为引用(或指针)传递给 FSM。
其他。
这取决于你的情况,但我有一种我通常使用的方法。
可能是 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);
}
我正在使用 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大量的。我觉得把工作和状态机分开是有意义的。
保持可读、可维护和可扩展的设计哪个更有意义?
在 FSM 的方法中执行业务逻辑 class(我担心这会将状态管理与工作过于紧密地混合在一起)。
在实例化 FSM 的父级中执行业务逻辑。 FSM 将需要一个指向父级的指针,而父级将需要实现 FSM 理解的接口(或者 FSM 实现将需要#include 父级的声明)。
在 FSM 实例化并拥有的新 class 中执行业务逻辑。
在一个新的 class 中执行业务逻辑,它由父级实例化并拥有,但作为引用(或指针)传递给 FSM。
其他。
这取决于你的情况,但我有一种我通常使用的方法。
可能是 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);
}