狀態模式的高效運用 3

2021-04-01 17:35:22 字數 1590 閱讀 4875

在標準state模式的實現中,有幾個地方讓人覺得不爽。首先,所有狀態物件要處理的訊息都必須在抽象狀態類中申明;其次由於所有訊息處理函式都是虛函式,一方面虛函式表占用記憶體,另一方面增加了呼叫的間接性,導致效率有所降低(當然這是相對的,也可能不是什麼大問題)。

在實際運用當中,有一種公認的比較高效的狀態機實現,其核心就是:把狀態當成成員函式(指標)!此話怎講?還是看看**來得直接。

在:《practical statecharts in c/c++ quantum programming for embedded systems》一書中,作者miro samek博士提供了乙個實現,我這裡簡單列一下:

class qf**

    virtual ~qf**()

    void init(qevent const *e = 0)

    void dispatch(qevent const *e)

    qf**state getstate() const

    static char const *getversion();

protected:

    void tran(qf**state target)

   #define qf**_tran(target_) (tran(q_static_cast(qf**state, target_)))

private:

    qf**state mystate;

};

我們看到,qf**代表乙個平面狀態機基類,它儲存了當前的狀態mystate,而這個當前狀態的型別是qf**state,檢視定義可以知道它是乙個類成員函式指標。當這個狀態機物件初始化時,它給使用者提供乙個hook,讓使用者決定轉換到什麼初始狀態(使用者必須提供initial初始狀態轉換函式)。以後當有訊息進來時,狀態機直接委託給當前狀態處理(通過dispatch函式)。狀態的躍遷是非常輕量級的,只是乙個類成員函式指標的賦值。

我們來看看要怎樣使用這個狀態機基類:

class myf** : public qf**

protected:

    void initial(qevent const *e);

    void state1(qevent const *e);

    void state2(qevent const *e);

    void state3(qevent const *e);

    //...

private:

    //private date and method

};

void basiccomponent::initial (cmessage *pmsg)



使用者在寫自己的狀態機時,必須提供initial函式,並且在裡面呼叫qf**_tran躍遷到初始狀態,接下來所有發給狀態機處理的事件都交由這個狀態處理,在裡面可以躍遷到其他狀態,實現狀態機的狀態轉換圖。

可以看到,沒有龐大的虛函式表從而節省記憶體,並且狀態轉換非常便捷,同時這種實現也省略了列舉狀態的開銷,簡直是居家旅行之必備良藥。

設計模式 3 狀態設計模式State

狀態模式用來改變物件的行為,當狀態發生變化時,行為也隨著發生變化,和switch分支語句有點類似,比如如下的 public class creatureelse 轉換標識 public void kiss public static void main string args greet 方法在業務...

棧的運用(3)

問題描述 試寫乙個判別表示式中開,閉括號是否配對出現的演算法 問題分析 這道題很簡單,表示式存入陣列中,判斷,開,閉括號的個數相等,但是也要注意順序,你不能出現這樣的情況 這個就不是正確的表示式了,也就是說兩個匹配的操作符之間不能有其他的操作符。想到昨天做的簡答題,把運算子入棧再去判斷。int ma...

設計模式 10 狀態模式(事務的狀態)

要點 例項 將每個狀態的行為區域性化到它自己的類中 將容易產生問題的if語句刪除,以方便日後的維護。讓每乙個狀態 對修改關閉 讓糖果機 堆擴充套件開放 因為可以加入新的狀態類 建立乙個新的 基和類結構,這更能對映萬 能糖果公司的圖,而且更容易閱讀和理解 允許物件在內部狀態改變時改變它的行為,物件看起...