状态机的C ++代码 [英] C++ code for state machine

查看:187
本文介绍了状态机的C ++代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个用C ++编码的面试问题:


为自动售货机编写代码:从一个简单的开始只是出售一种类型的项目。所以两个状态变量:金钱和库存,会做。


我的回答:



我会使用一个状态机, 3-4状态。使用枚举变量来指示状态并使用switch case语句,其中每个案例都具有对应于每个状态的操作,并保持在循环中以从一个状态移动到另一个状态。



下一个问题:


但是使用switch case语句不会规模井用于更多的状态被添加和修改在一个状态的现有操作。你将如何处理这个问题?


我当时无法回答这个问题。但后来想到,我可能:




  • 对于不同的状态有不同的函数(每个函数对应一个状态)

  • 有一个 std :: map from(string,function)其中string表示调用相应的状态函数的状态。

  • main函数有一个字符串变量(从初始状态开始),并在循环中调用与该变量对应的函数。每个函数执行所需的操作,并将新状态返回到主函数。



我的问题是:




  • 是关于大规模软件系统上下文中的可扩展性的switch-case语句的问题?

  • 如果是这样,我的解决方案(目前我觉得比有长线性代码有点模块化)要解决问题?



面试问题是来自C ++成语和大型软件系统的设计模式的答案。


<考虑使用表而不是 switch 语句。一列可以是转换标准,另一列是目标状态。



这很好地缩放,因为你不必改变表处理函数;只需向表中添加另一行即可。

  + ----------------- -  + --------------------- + --------------- + 
|当前状态ID |转换标准|下一状态ID |
+ ------------------ + --------------------- + ---- ----------- +
| | | |
+ ------------------ + --------------------- + ---- ----------- +

在我的代码中,我们使用列的函数指针,而不是下一个状态ID。该表是具有定义的访问器函数的单独文件。有一个或多个include语句来解析每个函数指针。



编辑1:单独表文件的示例



table.h



  #ifndef TABLE_H 
#define TABLE_H

struct Table_Entry
{
unsigned int current_state_id;
unsigned char transition_letter;
unsigned int next_state_id;
};

Table_Entry const * table_begin(void);
Table_Entry const * table_end(void);

#endif // TABLE_H

table.cpp:

  #includetable.h

static const Table_Entry my_table [] =
{
//当前转换下一个
//状态ID字母状态ID
{0,'A',1},//从0 goto 1如果字母是'A' 。
{0,'B',2},//从0 goto 2如果字母是'B'。
{0,'C',3},//从0 goto 3如果字母是'C'。
{1,'A',1},//从1 goto 1如果字母是'A'。
{1,'B',3},//从1 goto 3如果字母是'B'。
{1,'C',0},//从1 goto 0如果字母是'C'。
};

static const unsigned int TABLE_SIZE =
sizeof(my_table)/ sizeof(my_table [0]);


Table_Entry const *
table_begin(void)
{
return& my_table [0];
}


Table_Entry const *
table_end(void)
{
return& my_table [TABLE_SIZE];
}

state_machine.cpp
$ b

  #includetable.h
#include< iostream&

using namespace std; //因为我很懒。

void
Execute_State_Machine(void)
{
unsigned int current_state = 0;
while(1)
{
char transition_letter;
cout<< 当前状态:< current_state<< \\\
;
cout<< 输入转换字母:;
cin>> transition_letter;
cin.ignore(1000,'\\\
'); / *吃掉输入流中的'\\\
'* /
Table_Entry const * p_entry = table_begin();
Table_Entry const * const p_table_end = table_end();
bool state_found = false;
while((!state_found)&&(p_entry!= p_table_end))
{
if(p_entry-> current_state_id == current_state)
{
if(p_entry-> transition_letter == transition_letter)
{
cout< State found,transitioning
<< 从状态<< current_state
<< ,到状态< p_entry-> next_state_id
<< \\\
;
current_state = p_entry-> next_state_id;
state_found = true;
break;
}
}
++ p_entry;
}
if(!state_found)
{
cerr<< 找不到转换字母,当前状态没有改变。
}
}
}


This was an interview question to be coded in C++:

Write code for a vending machine: Start with a simple one where it just vends one type of item. So two state variables: money and inventory, would do.

My answer:

I would use a state machine which has about 3-4 states. Use an enum variable to indicate the state and use a switch case statement, where each case has the operations to be done corresponding to each state and stay in a loop to move from one state to another.

The next question:

But using a switch case statement does not "scale well" for more states being added and modifying existing operations in a state. How are you going to deal with that problem?

I couldn't answer this question at that time. But later thought, I can probably:

  • have different functions for different states (each function corresponding to a state)
  • have an std::map from (string, function) where string indicates state to call the corresponding state function.
  • The main function has a string variable (starting in initial state), and calls the function corresponding to that variable in a loop. Each function does the operations needed and returns the new state to the main function.

My questions are:

  • What is the problem with switch-case statements with respect to scalability in the context of large scale software systems?
  • If so is my solution (which currently I feel is a bit more modular than having long linear code) going to resolve the problem?

The interview question is expecting answers from C++ idioms and design patterns for large scale software systems.

解决方案

Consider using tables instead of switch statements. One column could be the transition criteria and another column is the destination state.

This scales nicely because you don't have to change the table processing function; just add another row to the table.

+------------------+---------------------+---------------+
| Current state ID | transition criteria | Next state ID |
+------------------+---------------------+---------------+
|                  |                     |               |
+------------------+---------------------+---------------+

In my code at work, we use a column of function pointers rather than the "Next state ID". The table is a separate file with accessor functions defined. There is one or more include statements to resolve each function pointer.

Edit 1: Example of separate table files.

table.h

#ifndef TABLE_H
#define TABLE_H

struct Table_Entry
{
    unsigned int  current_state_id;
    unsigned char transition_letter;
    unsigned int  next_state_id;
};

Table_Entry const *    table_begin(void);
Table_Entry const *    table_end(void);

#endif // TABLE_H

table.cpp:

#include "table.h"

static const Table_Entry    my_table[] =
{
    //  Current   Transition     Next
    //  State ID    Letter     State ID
    {    0,          'A',        1}, // From 0 goto 1 if letter is 'A'.
    {    0,          'B',        2}, // From 0 goto 2 if letter is 'B'.
    {    0,          'C',        3}, // From 0 goto 3 if letter is 'C'.
    {    1,          'A',        1}, // From 1 goto 1 if letter is 'A'.
    {    1,          'B',        3}, // From 1 goto 3 if letter is 'B'.
    {    1,          'C',        0}, // From 1 goto 0 if letter is 'C'.
};

static const unsigned int  TABLE_SIZE =  
    sizeof(my_table) / sizeof(my_table[0]);


Table_Entry const *
table_begin(void)
{
    return &my_table[0];
}


Table_Entry const *
table_end(void)
{
    return &my_table[TABLE_SIZE];
}  

state_machine.cpp

#include "table.h"
#include <iostream>

using namespace std;  // Because I'm lazy.

void
Execute_State_Machine(void)
{
    unsigned int current_state = 0;
    while (1)
    {
        char transition_letter;
        cout << "Current state: " << current_state << "\n";
        cout << "Enter transition letter: ";
        cin >> transition_letter;
        cin.ignore(1000, '\n'); /* Eat up the '\n' still in the input stream */
        Table_Entry const *  p_entry = table_begin();
        Table_Entry const * const  p_table_end =  table_end();
        bool state_found = false;
        while ((!state_found) && (p_entry != p_table_end))
        {
            if (p_entry->current_state_id == current_state)
            {
                if (p_entry->transition_letter == transition_letter)
                {
                    cout << "State found, transitioning"
                         << " from state " << current_state
                         << ", to state " << p_entry->next_state_id
                         << "\n";
                    current_state = p_entry->next_state_id;
                    state_found = true;
                    break;
                }
             }
             ++p_entry;
         }
         if (!state_found)
         {
             cerr << "Transition letter not found, current state not changed.\n";
         }
    }
}

这篇关于状态机的C ++代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆