Bir çocuk durum makinesi, kontrolü ana durum makinesine nasıl bırakabilir?


9

Üst düzey durum makinemin bazı durumları ve kenarları var. Buna ana durum makinesi diyeceğim.

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

Üst durum makinesindeki herhangi bir durum bir durum makinesi de olabilir. Bu çocuklara devlet makinesi diyeceğim.

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

Üst durum makinesi A'dan B'ye geçiş yaparsa, B'nin durum makinesi devreye girer. B'nin çalışması bittiğinde, üst durum makinesine kontrolü bırakıp C durumuna geçişi nasıl yapmalıdır? Hangi tasarım desenini kullanıyorsunuz?

Merak ediyorsanız, ana devlet makinelerinde çocuk devlet makineleri var, çünkü kesin projem oldukça karmaşık ve bir çocuk devletinin iç işleyişini kapsüllemek doğal.


B0, B1 ve B2'nin, dış dünyanın tek bir birim olarak gördüğü bir şeyin bileşenleri olduğunu bilmeleri gerektiğini tahmin ediyorum. Yani belki de B0, B1 ve B2'yi içeren bir MachineContainersınıfa sahip olmanız gerekir Bve B2 sona erdiğinde kontrole geri geçer ve daha sonra C'ye geçer ... Aslında böyle bir şey denemedim. Bu ilginç bir problem!
Hayal kırıklığına

2
Sorunuzun ya açık bir cevabı var ya da sorunuz çok açık değil. Ebeveynin bakış açısından, bunu tam olarak alt durum makinelerine sahip olmayan bir durum makinesini uygulayacağınız gibi uygulamalısınız. Durumlar, çocuk devlet makineleri kullanılarak uygulanmakta, ancak bu, ebeveyni hiç etkilememektedir. Ayrıca çıkıştan sonra sadece ebeveyn seviyesi olayları oluşturmaları dışında çocuk devlet makinelerini etkilememelidir.
Dunk

Yanıtlar:


5

Her durum makinesinin bir tür olay işleyicisi ve bu olayları tetiklemek için bir aracı vardır. Bu işleyici, mevcut durumu ve olay türünü girdi olarak alır, yeni durumu seçer ve isteğe bağlı olarak bazı yan etki kodları çalıştırır.

Esasen, durumdayken B, ana olay işleyiciniz tanımadığı tüm olayları olay işleyicisine iletir Bve durumunda kalır B. Ne zaman Bgeçiş istiyor C, ana olay işleyicisi uygun olayı nakleder.


2

Eğer okudunuz Taoup bu bölümüne ? Bunu gerçekleştirmenin birkaç farklı yolu vardır, ancak bunların çoğu devlet makinelerinizi nasıl bölüştüğünüze bağlıdır . Ayrı süreçler mi? İş Parçacığı? Nesneler?

Onları nasıl inşa ettiğinizi anlayın ve iletişim kurmaları için kanonik bir yol olup olmadığını görün. Biri yoksa, sisteminizi yanlış tasarlıyor olabilirsiniz.

Benim için, ayrı süreçlere bakardım, stdin ve stdout'u birbirine bağlarım. Çocuk devlet makinesi daha sonra tek başına olur, stdin üzerinde hareket eder ve stdout üzerinde çıkış yapar. Alt işlemi başlatmak, boruları bağlamak ve daha sonra veriyi boşaltmak ve sonuçları beklemek ana durum makinesinin işi haline gelir. Tüm bu şeyler zaten tüm modern dillerde yapılmıştır, bu yüzden yapılması kolay olmalıdır.


1

İki durum makinesini ayırın ve aralarından geçen iletiyi kullanın. Böylece, durum makinesi 1 ABC'den devam eder, burada durum B'de durum makinesinden 2 mevcut sonuçları kontrol eder. Çıktı değiştiyse, durum makinesi 1 bunu açıklayabilir ve durum makinesi 2'nin herhangi bir farkındalığa sahip olması gerekmez durum makinesinin 1 aslında nasıl çalıştığına dair. Gibi bir şey:

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

Çözüm, 1) A'nın alt durumlarının B'nin alt durumlarına görünür olup olmadığına bağlıdır. 2) AB ve C ortak bir ebeveynden türemiştir. Ortak bir ebeveynleri varsa ve görünürlük evrenselse, B'nin alt durumundan A'nın alt durumuna geçmek için çok fazla sorun yaşamamalısınız.

Bunları ad alanları aracılığıyla izole ettiyseniz ve / veya A, B ve C ortak bir ana öğeye sahip değilseniz, en iyi yolunuz A, B ve C makineleri için harici bir durum değişikliği sürücüsü kullanmaktır. Bu bir olay işleyici aracılığıyla yapılabilir. Sadece B'de ortaya çıkan olayları dinleyebilen ve olayı temel alarak kendi alt durumuna geçiş yapabilen A'da bir gözlemciye sahip olun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.