browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

一个基于 bind 与 function 的状态机框架实现

Posted by on 2014 年 01 月 01 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

当程序所面向的实际问题拥有多个状态以及较为复杂的分支时,状态机 往往是一个较为合适的解决方案。于我而言,出于函数粒度控制的偏好,我更喜欢使用 状态模式(State Pattern) 来实现状态机,而不是大坨碍眼的 switch-case 或 if-else;另外,我希望每个状态的处理器更为灵活,能够不受虚函数既定规格(参数)的限制,于是我选择了 bind 和 function。

需要说明的是,我仍然在使用古老的 VS2008 + TR1,那些用着 C++ 11 的想要表达优越感的骚年们最好洗洗睡吧。

好了,不说废话了。那么我先列出状态上下文及调用部分的代码吧,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Context
{
public:
    Context(void) : m_curstep(NULL) { /* Nothing */ }
public:
    void Initialize(void)
    {
        m_curstep = new State(std::tr1::bind(&Context::Step1, this));
    }
    bool DoNextStep(void)
    {
        State *step = (*m_curstep)();
        delete m_curstep;
        m_curstep = step;
        return NULL != step;
    }
private:
    State* Step1(void)
    {
        std::cout << "Context::Step1" << std::endl;
        return new State(std::tr1::bind(&Context::Step2, this, 2));
    }
    State* Step2(int param)
    {
        std::cout << "Context::Step2, param = " << param << std::endl;
        return new State(std::tr1::bind(&Context::FinalStep, this));
    }
    State* FinalStep(void)
    {
        std::cout << "Context::FinalStep" << std::endl;
        return NULL;
    }
private:
    State *m_curstep;
};
 
int main(void)
{
    Context foo;
    foo.Initialize();
 
    while (foo.DoNextStep()) {
        ;
    }
 
    return EXIT_SUCCESS;
}

简单说明一下:

  1. Step1、Step2 和 FinalStep 代表状态机中每一个状态的处理器。
  2. 由于使用了 bind,因此状态处理函数的参数可以是任意的。
  3. 状态处理函数的返回值必须是下一个需要处理的状态。示例中函数的实现做到了最简,而在实际的实现中,函数体可以包含较小篇幅的分支处理以决定下一个状态。

事实上,在实现这个框架之前,我的预期是直接以一个 tr1::function 指针来作为 m_curstep 成员的。但是在实际堆码的时候却发现这样做将导致模板参数的递归定义,这一点直接从语法上限制了我。于是,我只能使用继承的方法来规避这个限制,便有了如下的 State 实现:

1
2
3
4
5
6
class State : public std::tr1::function<State* ()>
{
    typedef std::tr1::function<State* ()> Base;
public:
    State(Base f) : Base(f) { /* Nothing */ }
};

订阅本站

没有评论

(Required)
(Required, will not be published)