the*_*row 5 c state-machine hsm
我对如何实现我的状态机感到有点困惑.
我已经知道它是分层的,因为一些州共享相同的行动.
我通过这些参数确定我需要做什么:
我的层次结构由Class决定,OpCode表示操作.
衍生可以使用操作码的基础和具体可以使用操作码两者的基础和衍生.
天真的实现如下:
void (*const state_table [MAX_CLASSES][MAX_OPCODES]) (state *) {
{base_state1, base_state2, NULL, NULL},
{base_state1, base_state2, derived_state1, NULL},
{base_state1,base_state2, derived_state1, specific_state3},
};
void dispatch(state *s)
{
if (state_table[s->Class][s->OpCode] != NULL)
state_table[s->Class][s->OpCode](s);
}
Run Code Online (Sandbox Code Playgroud)
这将变得难以维持.
还有另一种方法将状态映射到超类吗?
编辑:
进一步calcualtion使我认为,我可能会用最如果不是所有的操作码,但我不会用所有的类提供给我.
另一个澄清:
一些OpCodes可能通过多个派生类和基类共享.
例如:
我有另一个名为 MyGroup的类,它是一个Derived类.它有OpCodes: STATE_FLIP,STATE_FLOP.
第三个类是一个 名为ThingInMyGroup的特定类,它具有OpCode: STATE_FLIP_FLOP_AND_FLOOP.
因此,从服务器发送包含Any类的消息,在所有客户端中接收并处理.
与A级消息MyGroup的是从服务器发送,收到的所有客户端和处理只对属于客户MYGROUP,任何操作码的有效期为在任何类是有效的MyGroup的类.
从服务器发送带有ThingInMyGroup类的消息,在所有客户端中收到并仅在属于MyGroup的客户端上处理并且是ThingInMyGroup*,任何对Any类和MyGroup类有效的**OpCode对ThingInMyGroup类都有效.
收到消息后,客户端将相应地ACK/NACK.
我不喜欢使用switch case或const数组,因为当它们变大时它们将变得不可维护.
我需要一个灵活的设计,让我:
有几种方法可以解决这个问题。这是一个:
typedef unsigned op_code_type;
typedef void (*dispatch_type)(op_code_type);
typedef struct hierarchy_stack hierarchy_stack;
struct hierarchy_stack {
dispatch_type func;
hierarchy_stack *tail;
};
void dispatch(state *s, hierarchy_stack *stk) {
if (!stk) {
printf("this shouldn't have happened");
} else {
stk->func(s, stk->tail);
}
}
void Base(state *s, hierarchy_stack *stk ) {
switch (s->OpCode) {
case bstate1:
base_state1(s);
break;
case bstate2:
base_state(2);
break;
default:
dispatch(s, stk);
}
}
void Derived(state *s, hierarchy_stack *stk ) {
switch(s->opcode) {
case dstate1:
deriveds_state1(s);
break;
default:
dispatch(s, stk);
}
}
...
Run Code Online (Sandbox Code Playgroud)
这会很好地本地化您的“类”,因此,如果您决定 Derived 需要 100 个以上的方法/操作码,那么您只需编辑用于定义操作码的方法和枚举(或其他内容)。
另一种更动态的处理方法是在每个“类”中都有一个父指针,该指针指向将处理它无法处理的任何内容的“类”。
2D 表方法快速且灵活(对于操作码 0,Derived 可能具有与 Base 不同的处理程序),但增长速度很快。