Frage

Ich bin ein wenig verwirrt darüber, wie meine Zustandsmaschine zu implementieren.
Ich weiß schon, es ist hierarchisch, da einige Staaten die gleiche Aktion teilen.
Ich bestimme, was ich mit diesen Parametern zu tun:

  • Klasse (Werte sind: Basis Abgeleitet Spezifische )
  • OpCode
  • Parameter 1 - optional
  • Parameter 2 - optional

Meine Hierarchie wird durch die Klasse bestimmt und die OpCode für die Aktion.
Abgeleitet verwenden können, die OpCodes von Basis und Spezifische verwenden OpCodes der beiden < em> Basis und Abgeleitet .
Die naive Implementierung ist die folgende:

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);
}

Dies wird sich wirklich schnell wartbaren.
Gibt es einen anderen Weg, um den Zustand zu einem übergeordneten Klasse abzubilden?

EDIT:
Weitere calcualtion führt mich zu glauben, dass ich wahrscheinlich am meisten verwenden werden, wenn nicht alle OpCodes , aber ich werde nicht alle der Klassen zur Verfügung zu mir verwenden.
Eine weitere Klarstellung:
Einige OpCodes könnte durch mehr geteilt wird abgeleitet und Basis Klassen .
Zum Beispiel:

  • Ich habe eine Klasse Namen Alle die eine Basis Klasse. Es hat die OpCodes . state_on , STATE_OFF , STATE_SET
  • Ich habe eine andere Klasse genannt MyGroup , das ist eine Abgeleitet Klasse. Es hat die OpCodes : STATE_FLIP , STATE_FLOP .

  • Die dritte Klasse ist ein Spezifische genannt Klasse ThingInMyGroup die hat die OpCode : STATE_FLIP_FLOP_AND_FLOOP .

So eine Nachricht mit Klasse Alle wird von dem Server, in allen Clients und verarbeitet empfangen gesendet.

Eine Nachricht mit Klasse MyGroup wird vom Server gesendet, in allen Clients empfangen und verarbeitet nur auf Clients, die zu gehören MyGroup jeder OpCodes , die für die Alle Klasse gelten für die MyGroup Klasse gültig sind.

Eine Nachricht mit Klasse ThingInMyGroup wird vom Server gesendet, in allen Clients empfangen und verarbeitet nur auf Clients, die zu gehören MyGroup und ThingInMyGroup *, alle ** OpCodes , die für die gültig sind Any Klasse und MyGroup Klasse gelten für die ThingInMyGroup Klasse.

Nach einer Meldung des Client empfangen wird, wird die ACK / NACK entsprechend.

ich lieber nicht verwenden Schalter Fälle oder const-Arrays, wie sie wartbaren wird, wenn sie größer werden.
Ich brauche ein flexibles Design, das mir erlaubt:

  1. So geben Sie die OpCodes sind verfügbar für jede Klasse .
  2. Um eine übergeordnete Klasse angeben, für jede Klasse und durch diese Spezifikation mir zu erlauben, den Funktionszeiger aufrufen, die durch den Strom dargestellt wird OpCode .
War es hilfreich?

Lösung

Es gibt mehrere Möglichkeiten, dieses zu beschäftigen. Hier ist eine:

bearbeiten - mit Hierarchie für allgemeine Zwecke hinzugefügt

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);
    }
}
... 

HINWEIS: Alle Funktionsaufrufe sind Endaufruf

.

Dieses lokalisiert Ihre „Klasse“ es ein gutes Stück so, dass, wenn Sie feststellen, dass Abgeleitet Bedürfnisse 100 mehr Methoden entscheiden / Opcodes dann nur Sie zu bearbeiten Methoden und die ENUM (oder was auch immer), dass Sie Opcodes definieren verwenden.

Eine weitere, dynamische Art und Weise, um damit umzugehen wäre, einen Abstammungszeiger hat innerhalb jeder „Klasse“, die auf die „Klasse“ zeigten, dass alles behandeln würde, dass es nicht umgehen kann.

Der Ansatz 2D-Tabelle ist schnell und flexibel (Abgeleitete einen anderen Handler als Basis für Opcode 0 haben könnte), aber es wächst schnell.

Andere Tipps

schrieb ich ein kleines Tool, das basierend auf einem Mini-Sprachcode ähnlich wie Ihre naive Implementierung erzeugt. Die Sprache nur die state-Opcode-Aktion Beziehungen angegeben, alle Aktionen waren nur Funktionen C zu einem typedef entsprechen.

Es hat den HSM-Aspekt nicht behandeln, aber das wäre relativ leicht zu einer Sprache hinzuzufügen.

Ich würde empfehlen, diesen Ansatz - eine kleine Sprache erstellen, die eine saubere Art und Weise gibt die Zustandsmaschine zu beschreiben, und dann Code generieren basierend auf dieser Maschine Beschreibung. Auf diese Weise, wenn Sie einen neuen Staat im Monat von jetzt einfügen müssen, ist das Ganze nicht ein wirres Durcheinander zu bearbeiten.

Lassen Sie mich wissen, wenn Sie den Code wollen, und ich werde sicherstellen, dass es nach wie vor verfügbar irgendwo.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top