Як може дочірня державна машина повернути контроль до батьківської машини?


9

Моя державна машина верхнього рівня має деякі стани та краї. Я буду називати це батьківською машиною.

A ----> B ----> C

Будь-яка держава в батьківській машині може бути і державною машиною. Я буду називати цих дітей державними машинами.

           ___________
         /            \
A ----> |  B0->B1->B2  | ----> C
         \____________/

Якщо батьківська машина машини переходить від А до В, стан машини Б переймається. Як тільки B буде виконано, як слід відмовитися від управління батьківською машиною та переходом до стану C? Яку модель дизайну ви використовуєте?

Якщо вам цікаво, у мене є дитячі державні машини в машинах батьківських держав, тому що мій точний проект досить складний і закономірно включати внутрішню роботу дочірньої держави.


Я здогадуюсь, що B0, B1 і B2 повинні знати, що вони компоненти того, що зовнішній світ вважає єдиною одиницею. Тож, можливо, вам доведеться мати MachineContainerклас, Bякий містить B0, B1 і B2, і коли B2 закінчується, він передає керування назад до свого контейнера, який потім переходить до C ... Я ніколи насправді не намагався нічого подібного, хоча. Це цікава проблема!
FrustratedWithFormsDesigner

2
На ваше питання є або очевидний відповідь, або ваше питання не дуже зрозуміле. З точки зору батьків, ви повинні реалізувати його так, як ви реалізували б державну машину, яка не має дочірніх машин. Так буває, що держави реалізуються за допомогою дочірніх машин, але це зовсім не впливає на батьків. Це також не повинно впливати на дитячі державні машини, крім виходу, вони генерують лише події батьківського рівня.
Данк

Відповіді:


5

Кожна державна машина має певний обробник подій та спосіб викликати ці події. Цей обробник приймає за вхід існуючий стан і тип події, вибирає новий стан і необов'язково виконує код побічних ефектів.

По суті, перебуваючи в стані B, ваш основний обробник подій пересилає будь-які події, які він не визнає B, як обробник подій, і залишається в стані B. Коли Bхоче перейти до C, він надсилає відповідну подію до основного обробника події.


2

Ви читали цей розділ Taoup ? Існує кілька різних способів досягти цього, але багато з них залежать від того, як ви розділили свої державні машини. Це окремі процеси? Нитки? Об'єкти?

З’ясуйте, як ви їх побудували, і подивіться, чи є в них канонічний спосіб спілкування. Якщо такої не існує, можливо, ви неправильно проектуєте свою систему.

Для мене я би роздивився окремі процеси, з'єднуючи stdin та stdout разом. Потім дочірня машина стає автономною, діє на stdin і виводить на stdout. Завданням батьківської машини стає запускати дочірній процес, підключати труби, а потім скидати дані та чекати результатів. Усі ці речі вже зроблені всіма сучасними мовами, тому це робити легко.


1

Відокремте дві машини та використовуйте повідомлення, що проходять між ними. Таким чином, державна машина 1 буде виходити з ABC, де в стані B вона перевіряє поточні результати роботи від стаціонарної машини 2. Якщо результат змінився, стан 1 може врахувати це, а державна машина 2 не повинна мати обізнаності як насправді працює державна машина 1. Щось на зразок:

typedef struct StateMachine {
  void(*Update)(); // function to update the state machine
  int Data;        // generic temp holder to survive state contexts
  int State;       // current state of our state machine
  int *Message;    // pointer to a shared integer for message passing
};

int main(void) {
  int Message = 0;
  /* NewStateMachine would malloc the struct, pass in the int reference
   * and function pointer as well as add it to a circularly linked list */
  NewStateMachine(&Message, MainLoop);
  NewStateMachine(&Message, MinorLoop);
  StateMachine *Current = StateMachine_CLL.First;

  for(;;) {
    Current->Update(Current); /* Update the current state machine */
    Current = Current->Next;  /* And the advance to the next one */
  }
}

void MainLoop(StateMachine *this) {
  switch(this.State) {
  case 0:
    CloseCoolantTank(1); /* safe to call if valve already closed */
    CloseCoolantTank(2); /* safe to call if valve already closed */
    this.State = 1;
    break;
  case 1:
    /* we have a message, do something */
    if(*this.Message) this.State = 2;          
    /* otherwise stall at this state until we get a message */
    else this.State = 1;          
    break;
  case 2:
    if(*this.Message == 1) this.State = 3;      /* warm */
    else if(*this.Message == 2) this.State = 4; /* hot! */
    else this.State = 0;                        /* cooled down, shut off valves */
    this.Message = 0;                           /* clear the message */
    break;
  case 3:
    OpenCoolantTank(1); /* opens the valve, safe to call if already open */
    this.State = 2;     /* recheck for new message */
    break;
  case 4:
    OpenCoolantTank(2); /* opens the valve, safe to call if already open */
    this.State = 3;     /* also open coolant tank 1 for extra cooling */
    break;
  }
}

/* Monitor temperature and send messages on overheat */
void MinorLoop(StateMachine *this) {
  switch(this.State) {
  case 0:
    this.Data = ReadADCValue();
    this.State = 1;
    break;
  case 1:
    if(this.Data > 150) *this.Message = 2;
    else if(this.Data > 100) *this.Message = 1;
    this.State = 0;
    break;
  }
}

1

Рішення залежить від 1), чи бачать піддержави А види підрядів В. 2) Чи походять AB і C від спільного батька. Якщо у них є спільний батько, а видимість універсальна, у вас не повинно виникнути занадто великих проблем з переходом із підрядного стану В у підрядний стан А.

Якщо ви виділили їх через простори імен та / або A, B і C не мають спільного батька, то ваш найкращий спосіб - це мати драйвер зміни зовнішнього стану для машин A, B і C. Це можна зробити через обробник подій. Просто майте спостерігача в A, який може слухати події, підняті в B, і переходи до власного підреспубліки на основі події.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.