2010-02-02 122 views
8

有限狀態機在OOP中通常被認爲是糟糕的設計嗎?有限狀態機:糟糕的設計?

我聽到很多。而且,在我必須研究一個非常古老的,無證件的C++使用它之後,我傾向於同意。調試很痛苦。

關於可讀性/可維護性的問題呢?

+0

相關:http://stackoverflow.com/questions/1647631/c-state-machine-design – jldupont 2010-02-02 00:37:30

+7

作爲一個虔誠的Pastafarian ,FSM總是很好;) – richo 2010-02-02 00:56:55

+7

從來沒有詛咒過整個方法,因爲你正在考慮一個糟糕的實現。任何沒有記錄/難以調試的東西都不好,但是它的實現很糟糕。 – 2010-02-02 01:11:20

回答

16

FSM永遠不應該被認爲是壞的。他們太有用了,但不習慣他們的人往往會認爲他們很累。

有很多方法可以用OOP來實現。有些比其他人醜。你的低級別的人會使用switch語句,跳轉表,甚至是「goto」。

如果你正在尋找一個更乾淨的方法來做到這一點,我建議Boost's State Chart library,它建立只是爲了在C++中實現UML狀態圖。它利用現代模板技術,使事物更具可讀性。它也表現得很好。

+4

+1爲說明和Boost鏈接本身包含在第一頁由羅伯特C.馬丁稱爲「UML教程:有限狀態機」的PDF鏈接。任何人進入面向對象/狀態機的經典之作。 – SyntaxT3rr0r 2010-02-02 01:17:06

+0

「永不」是一個非常極端的觀點。國際海事組織在適用的情況下存在一些狹窄的情況。即使那樣,我還沒有看到一個乾淨的實現,不需要大量的紀律來正確使用(包括boost狀態圖)。 – Catskul 2016-12-28 20:49:21

1

我認爲如果代碼是有據可查的,使用面向對象的方法實現它是沒有問題的。大多數C/C++使用switch語句來實現FSM,如果機器很大,有時可能會降低可讀性。

最近我需要解析一個正則語言,並使用OOP方法實現FSM,代碼的可讀性和可維護性都很好。我的意思是,比使用大型開關語句好得多。

提示,在第一時刻,我已經實現了FSM包含狀態和包含轉換的狀態。然而,就我而言,事實證明有一個更好的方法可以讓一個班級代表FSM,其中包含一組州和另一個州的過渡。對我來說,克隆機器變得更加容易(這對我來說是必需的),並且具有更小的轉換功能。

我希望它有幫助, 卡洛斯。

2

我會說有限狀態機比其他解決相同問題的方法(比如匹配常規語言的問題)更容易調試。有關FSM的好處都在名稱之內......您可能有一個狀態機有15個狀態,所以您可以在顯示所有轉換的紙上繪製圖表。您可以使用該圖來找出系統的有用屬性,例如它接受哪些字符串以及它如何進入錯誤狀態。隨着更復雜的系統,圖表通常是困難的或不可能的。

即使那些說「gotos是邪惡的」的人認爲他們是實現狀態機的正確方式。 (當然,有些人認爲gotos總是邪惡的......但你不能取悅每個人)。

5

不能告訴你他們說什麼。

但OO和FSM sorta攻擊不同的問題域。在一個對象正在進行交互的領域 - 這就要求採用面向對象的方法。在世界處於一種或另一種狀態的領域 - 這就要求採用FSM設計。

實際上,您可以將這些設計與/以不同的抽象級別混合使用,這會比僅使用一種或另一種抽象更清晰。

6

有限狀態機是實現某些目標的工具。作爲任何工具,它們也可能被濫用。

他們並不是最親切的工具,但他們擅長的工作幾乎不可能通過其他方式實現(通常任何其他方法都註定要比機器差一千倍)。

該作業在經典等待狀態被禁止的條件下運行。

我必須閱讀觸摸屏。爲了閱讀這個位置,我必須通過SPI交換大約15個命令。我需要每秒100個讀數。我必須在每個命令之後等待大約1微秒,因爲在我繼續之前,相應的繁忙旗幟會消失。還有一些其他操作必須通過相同的界面來實現,例如設置對比度,更改模式,打開或關閉背光,讀取溫度。如果我爲每次等待執行while(BUSY_BIT);,我會在瞬間消耗所有的CPU。如果我做了sched_yield()usleep(1),我永遠不會達到我想要的讀數數量。唯一的辦法是有限狀態機。

但也有辦法讓有限狀態機玩起來也不錯。在幕後隱藏機器併爲開發人員提供功能。

迄今爲止,我的工作經驗是由2個基於3個不同有限狀態機的系統所支配。

  1. 一個大型的門戶網站,在每一步你從數據庫中檢索一些數據,並在此基礎上準備更多的查詢。在最後一步中,您使用數據生成HTML。每個任務 - 一個網頁模塊 - 被實現爲一個從引擎繼承的PHP類。狀態被保存在類變量中。每一步都是一個獨立的功能。在一個步驟結束時,優化存儲的查詢並通過緩存將其發送到引擎,並將答案提供回原始。
  2. 具有許多子系統的嵌入式設備。使用任務泵。每個模塊註冊一個從主循環中每秒調用多次的處理程序。處理程序可以使用狀態來保存靜態或類變量中的狀態。這種協作式多任務處理允許比在獨立線程中運行所有內存佔用更少的內存空間,允許通過註冊兩次任務來手動設置任務優先級,並使線程以高優先級運行,從而掩蓋系統其餘部分。
  3. 半解釋器。那個觸摸屏。函數調用及其等待狀態已註冊,但每個函數只被調用一次,然後從程序隊列中刪除。解釋器被稱爲taskpump的任務,執行有限數量的函數,直到遇到標記爲等待狀態的函數(或超出要調用的函數的數量)。然後繼續,直到等待狀態消失。其他任務將作業排序爲(有時很長的)要執行的函數序列,然後等待結果。通過這種方式,我可以將需要創建的狀態數量限制在約4個需要結果的位置。如果命令是「發送,不檢查結果」,如「設置對比度」,它們根本不需要離散狀態。因此,實際狀態是「等待事件並註冊請求的數據」,「等待測量」和「讀取結果並正確分配它們」。

如果在結構上或順序寫入,代碼將是簡單的兩倍,三倍更清晰。除了它不會工作,或者會表現糟糕的表現。

0

狀態機可以用來表示任何類的行爲。如果傳入事件的順序對Class行爲(組合類)無關緊要,則使用狀態模型不會帶來特殊好處。

但是,如果某個類的行爲取決於傳入事件的順序(順序類),則狀態機表示行爲分析和實現的最佳選擇。

如果您關心可讀性/可維護性,請使用圖形表示法。屬於不同工程領域的類的行爲示例以圖形和可執行形式在http://www.StateSoft.org - > State Machine Gallery中呈現。

-Janusz

+0

我不認爲這是真的,因爲類充分使用了圖靈語言。 https://upload.wikimedia.org/wikipedia/commons/a/a2/Automata_theory.svg – Catskul 2016-12-28 21:17:50

1

FSM的可以很容易理解和維護代碼是否結構化的正確途徑。我實現了在現有工作的FSM,這裏是一個骨架模板:

FSM