青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見(jiàn)諒!~
隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
數(shù)據(jù)加載中……

為L(zhǎng)inux應(yīng)用構(gòu)造有限狀態(tài)機(jī)方法

  有限自動(dòng)機(jī)(Finite Automata Machine)是計(jì)算機(jī)科學(xué)的重要基石,它在軟件開(kāi)發(fā)領(lǐng)域內(nèi)通常被稱(chēng)作有限狀態(tài)機(jī)(Finite State Machine),是一種應(yīng)用非常廣泛的軟件設(shè)計(jì)模式(Design Pattern)。本文介紹如何構(gòu)建基于狀態(tài)機(jī)的軟件系統(tǒng),以及如何利用Linux下的工具來(lái)自動(dòng)生成實(shí)用的狀態(tài)機(jī)框架。

  一、什么是狀態(tài)機(jī)

  有限狀態(tài)機(jī)是一種用來(lái)進(jìn)行對(duì)象行為建模的工具,其作用主要是描述對(duì)象在它的生命周期內(nèi)所經(jīng)歷的狀態(tài)序列,以及如何響應(yīng)來(lái)自外界的各種事件。在面向?qū)ο蟮能浖到y(tǒng)中,一個(gè)對(duì)象無(wú)論多么簡(jiǎn)單或者多么復(fù)雜,都必然會(huì)經(jīng)歷一個(gè)從開(kāi)始創(chuàng)建到最終消亡的完整過(guò)程,這通常被稱(chēng)為對(duì)象的生命周期。一般說(shuō)來(lái),對(duì)象在其生命期內(nèi)是不可能完全孤立的,它必須通過(guò)發(fā)送消息來(lái)影響其它對(duì)象,或者通過(guò)接受消息來(lái)改變自身。在大多數(shù)情況下,這些消息都只不過(guò)是些簡(jiǎn)單的、同步的方法調(diào)用而已。例如,在銀行客戶(hù)管理系統(tǒng)中,客戶(hù)類(lèi)(Customer)的實(shí)例在需要的時(shí)候,可能會(huì)調(diào)用帳戶(hù)(Account)類(lèi)中定義的getBalance()方法。在這種簡(jiǎn)單的情況下,類(lèi)Customer并不需要一個(gè)有限狀態(tài)機(jī)來(lái)描述自己的行為,主要原因在于它當(dāng)前的行為并不依賴(lài)于過(guò)去的某個(gè)狀態(tài)。

  遺憾的是并不是所有情況都會(huì)如此簡(jiǎn)單,事實(shí)上許多實(shí)用的軟件系統(tǒng)都必須維護(hù)一兩個(gè)非常關(guān)鍵的對(duì)象,它們通常具有非常復(fù)雜的狀態(tài)轉(zhuǎn)換關(guān)系,而且需要對(duì)來(lái)自外部的各種異步事件進(jìn)行響應(yīng)。例如,在VoIP電話(huà)系統(tǒng)中,電話(huà)類(lèi)(Telephone)的實(shí)例必須能夠響應(yīng)來(lái)自對(duì)方的隨機(jī)呼叫,來(lái)自用戶(hù)的按鍵事件,以及來(lái)自網(wǎng)絡(luò)的信令等。在處理這些消息時(shí),類(lèi)Telephone所要采取的行為完全依賴(lài)于它當(dāng)前所處的狀態(tài),因而此時(shí)使用狀態(tài)機(jī)就將是一個(gè)不錯(cuò)的選擇。

  游戲引擎是有限狀態(tài)機(jī)最為成功的應(yīng)用領(lǐng)域之一,由于設(shè)計(jì)良好的狀態(tài)機(jī)能夠被用來(lái)取代部分的人工智能算法,因此游戲中的每個(gè)角色或者器件都有可能內(nèi)嵌一個(gè)狀態(tài)機(jī)。考慮RPG游戲中城門(mén)這樣一個(gè)簡(jiǎn)單的對(duì)象,它具有打開(kāi)(Opened)、關(guān)閉(Closed)、上鎖(Locked)、解鎖(Unlocked)四種狀態(tài),如圖1所示。當(dāng)玩家到達(dá)一個(gè)處于狀態(tài)Locked的門(mén)時(shí),如果此時(shí)他已經(jīng)找到了用來(lái)開(kāi)門(mén)的鑰匙,那么他就可以利用它將門(mén)的當(dāng)前狀態(tài)轉(zhuǎn)變?yōu)?span lang="EN-US">Unlocked,進(jìn)一步還可以通過(guò)旋轉(zhuǎn)門(mén)上的把手將其狀態(tài)轉(zhuǎn)變?yōu)?span lang="EN-US">Opened,從而成功地進(jìn)入城內(nèi)。

clip_image001

  圖1 控制城門(mén)的狀態(tài)機(jī)

  在描述有限狀態(tài)機(jī)時(shí),狀態(tài)、事件、轉(zhuǎn)換和動(dòng)作是經(jīng)常會(huì)碰到的幾個(gè)基本概念。

  狀態(tài)(State) 指的是對(duì)象在其生命周期中的一種狀況,處于某個(gè)特定狀態(tài)中的對(duì)象必然會(huì)滿(mǎn)足某些條件、執(zhí)行某些動(dòng)作或者是等待某些事件。"

  事件(Event) 指的是在時(shí)間和空間上占有一定位置,并且對(duì)狀態(tài)機(jī)來(lái)講是有意義的那些事情。事件通常會(huì)引起狀態(tài)的變遷,促使?fàn)顟B(tài)機(jī)從一種狀態(tài)切換到另一種狀態(tài)。

  轉(zhuǎn)換(Transition) 指的是兩個(gè)狀態(tài)之間的一種關(guān)系,表明對(duì)象將在第一個(gè)狀態(tài)中執(zhí)行一定的動(dòng)作,并將在某個(gè)事件發(fā)生同時(shí)某個(gè)特定條件滿(mǎn)足時(shí)進(jìn)入第二個(gè)狀態(tài)。

  動(dòng)作(Action) 指的是狀態(tài)機(jī)中可以執(zhí)行的那些原子操作,所謂原子操作指的是它們?cè)谶\(yùn)行的過(guò)程中不能被其他消息所中斷,必須一直執(zhí)行下去。

  二、手工編寫(xiě)狀態(tài)機(jī)

與其他常用的設(shè)計(jì)模式有所不同,程序員想要在自己的軟件系統(tǒng)中加入狀態(tài)機(jī)時(shí),必須再額外編寫(xiě)一部分用于邏輯控制的代碼,如果系統(tǒng)足夠復(fù)雜的話(huà),這部分代碼實(shí)現(xiàn)和維護(hù)起來(lái)還是相當(dāng)困難的。在實(shí)現(xiàn)有限狀態(tài)機(jī)時(shí),使用switch語(yǔ)句是最簡(jiǎn)單也是最直接的一種方式,其基本思路是為狀態(tài)機(jī)中的每一種狀態(tài)都設(shè)置一個(gè)case分支,專(zhuān)門(mén)用于對(duì)該狀態(tài)進(jìn)行控制。下面的代碼示范了如何運(yùn)用switch語(yǔ)句,來(lái)實(shí)現(xiàn)圖1中所示的狀態(tài)機(jī):  

switch (state)

{

   // 處理狀態(tài)Opened的分支

   case (Opened): {

    // 執(zhí)行動(dòng)作Open

    open();

    // 檢查是否有CloseDoor事件

    if (closeDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Closed

     changeState(Closed)

    }

    break;

   }

  

   // 處理狀態(tài)Closed的分支

   case (Closed): {

    // 執(zhí)行動(dòng)作Close

    close();

    // 檢查是否有OpenDoor事件

    if (openDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Opened

     changeState(Opened);

    }

    // 檢查是否有LockDoor事件

    if (lockDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Locked

     changeState(Locked);

    }

    break;

   }

  

   // 處理狀態(tài)Locked的分支

   case (Locked): {

    // 執(zhí)行動(dòng)作Lock

    lock();

    // 檢查是否有UnlockDoor事件

    if (unlockDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Unlocked

     changeState(Unlocked);

    }

    break;

   }

  

   // 處理狀態(tài)Unlocked的分支

   case (Unlocked): {

    // 執(zhí)行動(dòng)作Unlock

    unlock();

    // 檢查是否有LockDoor事件

    if (lockDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Locked  

     changeState(Locked)

    }

    // 檢查是否有OpenDoor事件  

    if (openDoor()) {

     // 當(dāng)前狀態(tài)轉(zhuǎn)換為Opened

     changeSate(Opened);

    }

    break;

   }

  

}

 

  使用switch語(yǔ)句實(shí)現(xiàn)的有限狀態(tài)機(jī)的確能夠很好地工作,但代碼的可讀性并不十分理想,主要原因是在實(shí)現(xiàn)狀態(tài)之間的轉(zhuǎn)換時(shí),檢查轉(zhuǎn)換條件和進(jìn)行狀態(tài)轉(zhuǎn)換都是混雜在當(dāng)前狀態(tài)中來(lái)完成的。例如,當(dāng)城門(mén)處于Opened狀態(tài)時(shí),需要在相應(yīng)的case中調(diào)用closeDoor()函數(shù)來(lái)檢查是否有必要進(jìn)行狀態(tài)轉(zhuǎn)換,如果是的話(huà)則還需要調(diào)用changeState()函數(shù)將當(dāng)前狀態(tài)切換到Closed。顯然,如果在每種狀態(tài)下都需要分別檢查多個(gè)不同的轉(zhuǎn)換條件,并且需要根據(jù)檢查結(jié)果讓狀態(tài)機(jī)切換到不同的狀態(tài),那么這樣的代碼將是枯燥而難懂的。從代碼重構(gòu)的角度來(lái)講,此時(shí)更好的做法是引入checkStateChange()performStateChange()兩個(gè)函數(shù),專(zhuān)門(mén)用來(lái)對(duì)轉(zhuǎn)換條件進(jìn)行檢查,以及激活轉(zhuǎn)換時(shí)所需要執(zhí)行的各種動(dòng)作。這樣一來(lái),程序結(jié)構(gòu)將變得更加清晰:

  switch (state) {

  

   // 處理狀態(tài)Opened的分支

   case (Opened): {

    // 執(zhí)行動(dòng)作Open

    open();

    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Closed的分支

   case (Closed): {

    // 執(zhí)行動(dòng)作Close

    close();

    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Locked的分支

   case (Locked): {

    // 執(zhí)行動(dòng)作Lock

    lock();

    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Unlocked的分支

   case (Unlocked): {

    // 執(zhí)行動(dòng)作Lock

    unlock();

    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換

     performStateChange();

    }

    break;

   }

  

}

 

  在很長(zhǎng)一段時(shí)期內(nèi),使用switch語(yǔ)句一直是實(shí)現(xiàn)有限狀態(tài)機(jī)的唯一方法,甚至像編譯器這樣復(fù)雜的軟件系統(tǒng),大部分也都直接采用這種實(shí)現(xiàn)方式。但之后隨著狀態(tài)機(jī)應(yīng)用的逐漸深入,構(gòu)造出來(lái)的狀態(tài)機(jī)越來(lái)越復(fù)雜,這種方法也開(kāi)始面臨各種嚴(yán)峻的考驗(yàn),其中最令人頭痛的是如果狀態(tài)機(jī)中的狀態(tài)非常多,或者狀態(tài)之間的轉(zhuǎn)換關(guān)系異常復(fù)雜,那么簡(jiǎn)單地使用switch語(yǔ)句構(gòu)造出來(lái)的狀態(tài)機(jī)將是不可維護(hù)的。

  三、自動(dòng)生成狀態(tài)機(jī)

  為實(shí)用的軟件系統(tǒng)編寫(xiě)狀態(tài)機(jī)并不是一件十分輕松的事情,特別是當(dāng)狀態(tài)機(jī)本身比較復(fù)雜的時(shí)候尤其如此,許多有過(guò)類(lèi)似經(jīng)歷的程序員往往將其形容為"毫無(wú)創(chuàng)意"的過(guò)程,因?yàn)樗麄冃枰獙⒋罅康臅r(shí)間與精力傾注在如何管理好狀態(tài)機(jī)中的各種狀態(tài)上,而不是程序本身的運(yùn)行邏輯。作為一種通用的軟件設(shè)計(jì)模式,各種軟件系統(tǒng)的狀態(tài)機(jī)之間肯定會(huì)或多或少地存在著一些共性,因此人們開(kāi)始嘗試開(kāi)發(fā)一些工具來(lái)自動(dòng)生成有限狀態(tài)機(jī)的框架代碼,而在Linux下就有一個(gè)挺不錯(cuò)的選擇──FSMEFinite State Machine Editor)。

clip_image002

  圖2 可視化的FSME

  FSME是一個(gè)基于Qt的有限狀態(tài)機(jī)工具,它能夠讓用戶(hù)通過(guò)圖形化的方式來(lái)對(duì)程序中所需要的狀態(tài)機(jī)進(jìn)行建模,并且還能夠自動(dòng)生成用C++或者Python實(shí)現(xiàn)的狀態(tài)機(jī)框架代碼。下面就以圖1中城門(mén)的狀態(tài)機(jī)為例,來(lái)介紹如何利用FSME來(lái)自動(dòng)生成程序中所需要的狀態(tài)機(jī)代碼。

  3.1狀態(tài)機(jī)建模

  首先運(yùn)行fsme命令來(lái)啟動(dòng)狀態(tài)機(jī)編輯器,然后單擊工具欄上" "New"按鈕來(lái)創(chuàng)建一個(gè)新的狀態(tài)機(jī)。FSME中用于構(gòu)建狀態(tài)機(jī)的基本元素一共有五種:事件(Event)、輸入(Input)、輸出(Output)、狀態(tài)(State)和轉(zhuǎn)換(Transition),在界面左邊的樹(shù)形列表中可以找到其中的四種。

  狀態(tài)建模

  在FSME界面左邊的樹(shù)形列表中選擇"States"項(xiàng),然后按下鍵盤(pán)上的Insert鍵來(lái)插入一個(gè)新的狀態(tài),接著在右下方的"Name"文本框中輸入狀態(tài)的名稱(chēng),再在右上方的繪圖區(qū)域單擊該狀態(tài)所要放置的位置,一個(gè)新的狀態(tài)就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有狀態(tài)。

clip_image003

  圖3 狀態(tài)建模

  事件建模

  在FSME界面左邊的樹(shù)形列表中選" "Events"項(xiàng),然后按下鍵盤(pán)上的Insert鍵來(lái)添加一個(gè)新的事件,接著在右下方的"Name"文本框中輸入事件的名稱(chēng),再單擊"Apply"按鈕,一個(gè)新的事件就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有事件。

clip_image004

  圖4 事件建模

  狀態(tài)轉(zhuǎn)換是整個(gè)建模過(guò)程中最重要的一個(gè)部分,它用來(lái)定義有限狀態(tài)機(jī)中的一個(gè)狀態(tài)是如何切換到另一個(gè)狀態(tài)的。例如,當(dāng)用來(lái)控制城門(mén)的狀態(tài)機(jī)處于Opened狀態(tài)時(shí),如果此時(shí)有Close事件產(chǎn)生,那么狀態(tài)機(jī)的當(dāng)前狀態(tài)將切換到Closed狀態(tài),這樣一個(gè)完整的過(guò)程在狀態(tài)機(jī)模型中可以用closeDoor這樣一個(gè)轉(zhuǎn)換來(lái)進(jìn)行描述。

  要在FSME中添加這樣一個(gè)轉(zhuǎn)換,首先需要在界面左邊的樹(shù)形列表中選" "States"下的"Opened"項(xiàng),然后按下鍵盤(pán)上的Insert鍵來(lái)添加一個(gè)新的轉(zhuǎn)換,接著在右下角的"Name"文本框中輸入轉(zhuǎn)換的名字"closeDoor",在"Condition"文本框中輸入"Close"表明觸發(fā)該轉(zhuǎn)換的條件是事件Close的產(chǎn)生,在"Target"下拉框中選擇"Closed"項(xiàng)表明該轉(zhuǎn)換發(fā)生后狀態(tài)機(jī)將被切換到Closed狀態(tài),最后再單擊"Apply"按鈕,一個(gè)新的狀態(tài)轉(zhuǎn)換關(guān)系就定義好了,如圖5所示。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有轉(zhuǎn)換。

clip_image005

  圖5 轉(zhuǎn)換建模

  3.2 生成狀態(tài)機(jī)框架

  使用FSME不僅能夠進(jìn)行可視化的狀態(tài)機(jī)建模,更重要的是它還可以根據(jù)得到的模型自動(dòng)生成用C++或者Python實(shí)現(xiàn)的狀態(tài)機(jī)框架。首先在FSME界面左邊的樹(shù)形列表中選擇"Root"項(xiàng),然后在右下角的"Name"文本框中輸入狀態(tài)機(jī)的名字"DoorFSM",再?gòu)?span lang="EN-US">"Initial State"下拉列表中選擇狀態(tài)"Opened"作為狀態(tài)機(jī)的初始化狀態(tài)。

clip_image006

  圖6 設(shè)置初始屬性

  在將狀態(tài)機(jī)模型保存為door.fsm文件之后,使用下面的命令可以生成包含有狀態(tài)機(jī)定義的頭文件:

  [xiaowp@linuxgam" code]$ fsmc door.fsm -d -o DoorFSM.

  進(jìn)一步還可以生成包含有狀態(tài)機(jī)實(shí)現(xiàn)的框架代碼:

  [xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

  如果想對(duì)生成的狀態(tài)機(jī)進(jìn)行驗(yàn)證,只需要再手工編寫(xiě)一段用于測(cè)試的代碼就可以了:

  /*
   * TestFSM.cpp
   * 測(cè)試生成的狀態(tài)機(jī)框架
   */
  
  #include "DoorFSM.h"
  
  int main()
  {
   DoorFSM door;
   door.A(DoorFSM::Close);
   door.A(DoorFSM::Lock);
   door.A(DoorFSM::Unlock);
   door.A(DoorFSM::Open);
  }

  有限狀態(tài)機(jī)是由事件來(lái)進(jìn)行驅(qū)動(dòng)的,在FSME生成的狀態(tài)機(jī)框架代碼中,方法A()可以被用來(lái)向狀態(tài)機(jī)發(fā)送相應(yīng)的事件,從而提供狀態(tài)機(jī)正常運(yùn)轉(zhuǎn)所需要的"動(dòng)力"。狀態(tài)機(jī)負(fù)責(zé)在其內(nèi)部維護(hù)一個(gè)事件隊(duì)列,所有到達(dá)的事件都會(huì)先被放到事件隊(duì)列中進(jìn)行等候,從而能夠保證它們將按照到達(dá)的先后順序被依次處理。在處理每一個(gè)到達(dá)的事件時(shí),狀態(tài)機(jī)都會(huì)根據(jù)自己當(dāng)前所處的狀態(tài),檢查與該狀態(tài)對(duì)應(yīng)的轉(zhuǎn)換條件是否已經(jīng)被滿(mǎn)足,如果滿(mǎn)足的話(huà)則激活相應(yīng)的狀態(tài)轉(zhuǎn)換過(guò)程。

  使用下面的命令能夠?qū)⑸傻臓顟B(tài)機(jī)框架和測(cè)試代碼編譯成一個(gè)可執(zhí)行文件:

  [xiaowp@linuxgam code]$ g++ DoorFSM.cpp TestFSM.cpp -o fsm

由于之前在用fsmc命令生成狀態(tài)機(jī)代碼時(shí)使用了-d選項(xiàng),生成的狀態(tài)機(jī)框架中會(huì)包含一定的調(diào)試信息,包括狀態(tài)機(jī)中每次狀態(tài)轉(zhuǎn)換時(shí)的激活事件、轉(zhuǎn)換前的狀態(tài)、所經(jīng)歷的轉(zhuǎn)換、轉(zhuǎn)換后的狀態(tài)等,如下所示:

  [xiaowp@linuxgam code]$ ./fsm
  DoorFSM:event:'Close'
  DoorFSM:state:'Opened'
  DoorFSM:transition:'closeDoor'
  DoorFSM:new state:'Closed'
  DoorFSM:event:'Lock'
  DoorFSM:state:'Closed'
  DoorFSM:transition:'lockDoor'
  DoorFSM:new state:'Locked'
  DoorFSM:event:'Unlock'
  DoorFSM:state:'Locked'
  DoorFSM:transition:'unlockDoor'
  DoorFSM:new state:'Unlocked'
  DoorFSM:event:'Open'
  DoorFSM:state:'Unlocked'
  DoorFSM:transition:'openDoor'
  DoorFSM:new state:'Opened'

  3.3 定制狀態(tài)機(jī)

  目前得到的狀態(tài)機(jī)已經(jīng)能夠響應(yīng)來(lái)自外部的各種事件,并適當(dāng)?shù)卣{(diào)整自己當(dāng)前所處的狀態(tài),也就是說(shuō)已經(jīng)實(shí)現(xiàn)了狀態(tài)機(jī)引擎的功能,接下來(lái)要做的就是根據(jù)應(yīng)用的具體需求來(lái)進(jìn)行定制,為狀態(tài)機(jī)加入與軟件系統(tǒng)本身相關(guān)的那些處理邏輯。在FSME中,與具體應(yīng)用相關(guān)的操作稱(chēng)為輸出(Output),它們實(shí)際上就是一些需要用戶(hù)給出具體實(shí)現(xiàn)的虛函數(shù),自動(dòng)生成的狀態(tài)機(jī)引擎負(fù)責(zé)在進(jìn)入或者退出某個(gè)狀態(tài)時(shí)調(diào)用它們。

  仍然以控制城門(mén)的那個(gè)狀態(tài)機(jī)為例,假設(shè)我們希望在進(jìn)入每個(gè)狀態(tài)時(shí)都添加一部分處理邏輯。首在FSME界面左邊的樹(shù)形列表選擇"Outputs"項(xiàng),然后按下鍵盤(pán)上的Insert鍵來(lái)添加一個(gè)新的輸出,接著在右下方的"Name"文本框中輸入相應(yīng)的名稱(chēng),再單擊"Apply"按鈕,一個(gè)新的輸出就創(chuàng)建好了,如圖7所示。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有輸出。

clip_image007

  圖7 添加輸出

  當(dāng)所有的輸出都定義好之后,接下來(lái)就可以為狀態(tài)機(jī)中的每個(gè)狀態(tài)綁定相應(yīng)的輸出。首先在FSME界面左側(cè)的"States"項(xiàng)中選擇相應(yīng)的狀態(tài),然后從右下角的"Available"列表框中選擇與該狀態(tài)對(duì)應(yīng)的輸出,再單擊"<"按鈕將其添加到"In"列表中。用同樣的辦法可以為狀態(tài)機(jī)中的所有狀態(tài)設(shè)置相應(yīng)的輸出,同一個(gè)狀態(tài)可以對(duì)應(yīng)有多個(gè)輸出,其中In列表中的輸出會(huì)在進(jìn)入該狀態(tài)時(shí)被調(diào)用,而Out列表中的輸出則會(huì)在退出該狀態(tài)時(shí)被調(diào)用,輸出調(diào)用的順序是與其在In或者Out列表中的順序相一致的。

由于對(duì)狀態(tài)機(jī)模型進(jìn)行了修改,我們需要再次生成狀態(tài)機(jī)的框架代碼,不過(guò)這次不需要加上-d參數(shù):

  [xiaowp@linuxgam" code]$ fsmc door.fsm -o DoorFSM.h
  [xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

我們?cè)谛碌臓顟B(tài)機(jī)模型中添加了enterOpendenterClosedenterLockedenterUnlocked四個(gè)輸出,因此生成的類(lèi)DoorFSM中會(huì)包含如下幾個(gè)純虛函數(shù)

    virtual void enterOpened() = 0;
    virtual void enterLocked() = 0;
    virtual void enterUnlocked() = 0;
    virtual void enterClosed() = 0;

 

  顯然,此時(shí)生成的狀態(tài)機(jī)框架不能夠再被直接編譯了,我們必須從類(lèi)DoorFSM派生出一個(gè)子類(lèi),并提供對(duì)這幾個(gè)純虛函數(shù)的具體實(shí)現(xiàn):

  /*
   * DoorFSMLogic.h
   * 狀態(tài)機(jī)控制邏輯的頭文件
   */
  #include "DoorFSM.h"
  
  class DoorFSMLogic : public DoorFSM
  {
  
   protected:
   virtual void enterOpened();
   virtual void enterLocked();
   virtual void enterUnlocked();
   virtual void enterClosed();
  };

  正如前面所提到過(guò)的,這幾個(gè)函數(shù)實(shí)際上代表的正是應(yīng)用系統(tǒng)的處理邏輯,作為例子我們只是簡(jiǎn)單地輸出一些提示信息:

  /*
   * DoorFSMLogic.cpp
   * 狀態(tài)機(jī)控制邏輯的實(shí)現(xiàn)文件
   */
  #include "DoorFSMLogic.h"
  #include
  
  void DoorFSMLogic::enterOpened()
  {
    std::cout << "Enter Opened state." << std::endl;
  }
  
  void DoorFSMLogic::enterClosed()
  {
    std::cout << "Enter Closed state." << std::endl;
  }
  
  void DoorFSMLogic::enterLocked()
  {
    std::cout << "Enter Locked state." << std::endl;
  }
  
  void DoorFSMLogic::enterUnlocked()
  {
    std::cout << "Enter Unlocked state." << std::endl;
  }

  同樣,為了對(duì)生成的狀態(tài)機(jī)進(jìn)行驗(yàn)證,我們還需要手工編寫(xiě)一段測(cè)試代碼:

  /*
   * TestFSM.cpp
   * 測(cè)試狀態(tài)機(jī)邏輯
   */
  #include "DoorFSMLogic.h"
  
  int main()
  {
   DoorFSMLogic door;
   door.A(DoorFSM::Close);
   door.A(DoorFSM::Lock);
   door.A(DoorFSM::Unlock);
   door.A(DoorFSM::Open);
  }

  使用下面的命令能夠?qū)⑸傻臓顟B(tài)機(jī)框架和測(cè)試代碼編譯成一個(gè)可執(zhí)行文件:

[xiaowp@linuxgam code]$ g++ DoorFSM.cpp DoorFSMLogic.cpp TestLogic.cpp -o logic

  運(yùn)行結(jié)果如下所示:

  [xiaowp@linuxgam code]$ ./logic
  Enter Closed state.
  Enter Locked state.
  Enter Unlocked state.
  Enter Opened state.

  四、小結(jié)

  在面向?qū)ο蟮能浖到y(tǒng)中,有些對(duì)象具有非常復(fù)雜的生命周期模型,使用有限狀態(tài)機(jī)是描述這類(lèi)對(duì)象最好的方法。作為一種軟件設(shè)計(jì)模式,有限狀態(tài)機(jī)的概念雖然不算復(fù)雜,實(shí)現(xiàn)起來(lái)也并不困難,但它的問(wèn)題是當(dāng)狀態(tài)機(jī)的模型復(fù)雜到一定的程度之后,會(huì)帶來(lái)實(shí)現(xiàn)和維護(hù)上的困難。Linux下的FSME是一個(gè)可視化的有限狀態(tài)機(jī)建模工具,而且支持狀態(tài)機(jī)框架代碼的自動(dòng)生成,借助它可以更加輕松地構(gòu)建基于有限狀態(tài)機(jī)的應(yīng)用系統(tǒng)。

posted on 2008-12-14 18:40 肥仔 閱讀(750) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): 狀態(tài)機(jī) & 自動(dòng)機(jī) & 形式語(yǔ)言

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲第一免费播放区| 农村妇女精品| 快播亚洲色图| 久久国产精品色婷婷| 亚洲欧美中文另类| 欧美亚洲系列| 美女尤物久久精品| 亚洲经典自拍| 亚洲一区二区三区高清| 这里只有精品视频在线| 亚洲在线免费观看| 久久久中精品2020中文| 欧美高清在线精品一区| 亚洲国产精品999| 99综合在线| 久久久www成人免费无遮挡大片| 欧美成人资源网| 国产精品区二区三区日本| 黑人一区二区三区四区五区| 亚洲精品国产精品乱码不99| 亚洲男人的天堂在线| 久久在线播放| 亚洲精品在线观看视频| 亚洲欧美另类综合偷拍| 久久久欧美精品sm网站| 欧美三级在线播放| 国产欧美一区二区视频| 亚洲日韩欧美视频一区| 欧美在线日韩| 亚洲日韩视频| 99re6这里只有精品| 欧美在线国产精品| 欧美三级不卡| 亚洲精品午夜| 浪潮色综合久久天堂| a4yy欧美一区二区三区| 蜜臀久久99精品久久久画质超高清 | 亚洲高清av| 亚洲欧美日韩久久精品| 美日韩精品免费| 91久久精品网| 欧美一区二区三区播放老司机| 狼人天天伊人久久| 国产精品高潮呻吟久久av无限| 狠狠色丁香婷婷综合| 亚洲视频在线二区| 欧美激情视频一区二区三区免费| 亚洲一区在线观看免费观看电影高清| 久久影视精品| 国产真实精品久久二三区| 亚洲一区二区久久| 亚洲区国产区| 免费亚洲婷婷| 伊人精品在线| 久久久999| 亚洲综合欧美日韩| 欧美四级在线观看| 一区二区三区免费看| 亚洲国产综合在线| 男女精品视频| 亚洲国产mv| 欧美91精品| 久久一区二区三区四区五区| 国内精品久久久久久久影视蜜臀 | 国产女人aaa级久久久级| 亚洲一区综合| 亚洲一区在线直播| 国产精品一区二区黑丝| 欧美制服丝袜第一页| 欧美一区二视频在线免费观看| 国产日韩一区二区| 久久久久欧美精品| 久久精品主播| 亚洲黄网站在线观看| 91久久亚洲| 国产精品成人一区二区三区吃奶| 亚洲欧美999| 性欧美1819性猛交| 影音先锋国产精品| 亚洲国产欧美一区二区三区同亚洲| 久久综合一区二区| 99re这里只有精品6| 99国产一区二区三精品乱码| 国产精品成人免费精品自在线观看| 亚洲一级黄色av| 午夜日韩激情| 在线观看日韩av电影| 最新国产乱人伦偷精品免费网站 | 亚洲男女自偷自拍| 国语自产精品视频在线看8查询8| 欧美xxxx在线观看| 国产精品久久| 欧美成人免费在线视频| 欧美日韩综合视频| 噜噜爱69成人精品| 欧美日韩在线不卡一区| 狠狠色狠色综合曰曰| 日韩天堂av| 亚洲午夜免费视频| 在线不卡中文字幕| 夜夜躁日日躁狠狠久久88av| 国产精品午夜国产小视频| 美国三级日本三级久久99| 免费在线亚洲| 欧美一区精品| 欧美猛交免费看| 久久久99免费视频| 欧美区一区二区三区| 久久精品在线视频| 欧美啪啪成人vr| 久久乐国产精品| 欧美日韩一区二区精品| 久久综合给合| 国产精品女人毛片| 亚洲二区在线视频| 亚洲一二三区在线| 亚洲国产老妈| 香蕉av福利精品导航| 一区二区三区欧美在线观看| 久久一二三四| 久久人人爽人人爽爽久久| 欧美午夜不卡视频| 欧美高清你懂得| 狠狠噜噜久久| 欧美一区二区三区视频在线| 亚洲欧美日韩在线综合| 欧美日韩国产成人精品| 欧美激情二区三区| 1769国产精品| 久久久精品一品道一区| 久久国产精品黑丝| 国产精品免费福利| 亚洲视频在线观看免费| 亚洲一级黄色| 国产精品欧美一区二区三区奶水| 日韩视频免费在线| 一区二区三区四区国产| 欧美日韩大陆在线| 99精品黄色片免费大全| 一本高清dvd不卡在线观看| 欧美激情 亚洲a∨综合| 亚洲国产日韩欧美在线99| 91久久视频| 欧美另类一区| 亚洲一区二区三区四区在线观看| 亚洲午夜一区二区三区| 欧美亚州在线观看| 亚洲影音一区| 久久久久久亚洲精品杨幂换脸 | 欧美激情一区二区三级高清视频| 美脚丝袜一区二区三区在线观看| 韩日欧美一区| 久久久精品国产免大香伊| 免费h精品视频在线播放| 在线观看中文字幕亚洲| 美日韩免费视频| 亚洲精品午夜| 先锋影院在线亚洲| 国户精品久久久久久久久久久不卡 | 一本色道88久久加勒比精品| 欧美成ee人免费视频| 亚洲人成艺术| 亚洲香蕉在线观看| 国产女主播在线一区二区| 久久av一区二区三区漫画| 美女日韩欧美| 在线亚洲国产精品网站| 国产嫩草一区二区三区在线观看| 性高湖久久久久久久久| 欧美国产成人精品| 亚洲午夜伦理| 国语精品中文字幕| 欧美日韩免费高清| 久久激情五月婷婷| 亚洲精品国产精品乱码不99| 性色av一区二区怡红| 一区二区在线观看av| 欧美日韩中文字幕精品| 久久久91精品国产| 日韩香蕉视频| 久久综合久久久久88| 亚洲图片在线| 亚洲国产女人aaa毛片在线| 欧美午夜理伦三级在线观看| 久久理论片午夜琪琪电影网| 亚洲视频网站在线观看| 欧美国产日韩一区二区在线观看 | 欧美成人自拍| 欧美一区二区三区啪啪| 日韩午夜在线| 亚洲高清不卡在线观看| 久久精品在这里| 亚洲综合国产| 9久草视频在线视频精品| 精品成人在线观看| 国产精品亚洲片夜色在线| 欧美区一区二区三区| 欧美freesex8一10精品| 久久久欧美一区二区| 久久成人免费网|