2013-02-27 175 views
0

我目前正試圖想出一個用於編碼多層狀態機的乾淨設計,到目前爲止,我還沒有在有關C++中正常狀態機使用的文章中找到解決方案或其他。多層複雜狀態機

在層次結構的最底部,我們有原子狀態:a,b,c,...,x,y,z。 最重要的是,存在的複合狀態的第一層:A,B,C,D。 最後,在最頂部,有一個最終聚合根狀態X.

 X 
    A B C D 
a b c d e f g h... 

相反通常的狀態機,最低狀態由外部因素定義和確定;沒有可檢測到的事件可以改變它們,僅僅通過觀察就可以檢測到變化。

在原子狀態改變之後,他的第一個複合層具有一組可以採用的狀態,具體取決於較低狀態的組合。例如:a,b和c是A的「子」狀態:

a b c - A 
0 0 0 - 0 
1 0 0 - 1 
2 0 0 - x 
2 1 0 - 2 

等等...其中x未定義。

最後,根狀態根據組合狀態具有一組狀態 - 遵循與之前相同的邏輯。

到目前爲止,我嘗試了一種自頂向下的方法,其中根將調用到子狀態中,然後調用原子狀態來更新它們,級聯備份。

我也嘗試了一種自下而上的方法,其中原子狀態將更新並調用到子狀態中,這又會調用到根狀態。

在這兩種情況下,單個子狀態可能僅依賴於一個或多個原子狀態的事實使得狀態驗證非常複雜,並且最終得到不可接受的臃腫代碼。我覺得我需要一種不同的方法,但我堅持當前的設計。如果任何人有這種問題的經驗,並可以提供一些靈感,我真的很感激。

+0

看看http://www.complang.org/ragel/ – akira 2013-02-28 06:36:13

+0

它看起來非常interes但這並不能解決這個問題,因爲各州之間的過渡還不得而知 - 我們只能在發生狀態變化後才能觀察到狀態變化,並據此調整上層狀態。 – awishformore 2013-02-28 14:30:07

+0

你不知道如何從一個狀態轉換到另一個狀態?我的意思是,如果你處於'狀態',然後發生了事情,然後你處於'狀態A',你測量了一些標記當前狀態爲'A'的東西。所以,在那裏你有你已知的狀態改變者......你觀察到的東西。 – akira 2013-02-28 19:02:12

回答

0

一個快速思想:

1)複合物和原子態( 「A」, 「B」, 「C」 作爲observees和 「A」 作爲觀察者,等等之間觀察者模式..)

2)使用Pimpl idiom實現class-A來分離接口&實現細節,從而具有更多的控制權,並且在更改實現細節方面展現出更多的靈活性。

3)讓A類具有某種工廠抽象來創建&爲每個唯一狀態「A」管理專門的實現對象。 4)因此,只要a,b,c上的變化被「A」觀察到,Factory就會幫助檢索「A」的相應實現狀態並進行狀態變化。 在「A」和「X」之間應用相同的方法。

更詳細的佈局:

1)定義所需的接口(通用或抽象類)IX,IA,IA,IB,IC。

2)在界面IA,定義公共IaChanged式(Ia *),IbChanged(IB *)& IcChanged(IC *)方法來接收IA,IB & Ic的狀態變更通知(觀察者模式的回調方法)。

3)在原子界面Ia內部,Ic。Ic。定義公共註冊表(IA &)& private Notify()metods。 在接口1a中,

Where Notify() { foreach(observer in m_Observers) 
        observer->IaChanged(this); 
        } 

在接口1b中,

Where Notify() { foreach(observer in m_Observers) 
        observer->IbChanged(this); 
        } 

等等...

4)具有clases X,A,從各自的接口得到的,B,C。其中 - >代表「衍生」。其中 - >代表「衍生」。 5)讓A類定義A_implState(Pimpl Idiom),其中A_implState可以從新接口IA_implState派生,以保持通用性。

將類A_implState0,A_implState1,A_implState2,A_implStateX作爲IA_implState的專用版本。

其中,

class IA_implState 
    { 
     public: 
      virtual void processStateChange()=0; 
    }; 

    class A_implState0 : public IA_implState 
    { 
     public: 
      void processStateChange() 
      { 
       // do your stuff specific to State "0" of "A". 
      } 
    }; 

    class A_implStateX : public IA_implState 
    { 
     public: 
      void processStateChange() 
      { 
       // do your stuff specific to State "X" of "A". 
      } 
    };  
    so on... 

6)具有用於每個不同狀態IA_Impl之一專業化,基於:

a b c - A 
0 0 0 - 0 
1 0 0 - 1 
2 0 0 - x 
2 1 0 - 2 

7)在A類,每當IaChanged(IaPtr)或IbChanged (IbPtr)或IcChanged(IcPtr)被相應的觀察員觸發,將更改通知處理爲:

// a changed 
    void A::IaChanged(IaPtr a) 
    { 
    //Buffer Ia inside a member 
    m_pIa = a; 
    //Retrieve A-implementer based on the current state. 
    m_pimplA = m_implAContainer[GetCurrentState()]; // or use FactoryMethod or AbstractFactory pattern if required. 
    m_pimplA->processStateChange(); 
    } 

    // b changed 
    void A::IbChanged(IbPtr b) 
    { 
     //Buffer Ib inside a member 
     m_pIb = b; 
     m_pimplA = m_implAContainer[GetCurrentState()]; // use FactoryMethod or AbstractFactory pattern if required. 
     m_pimplA->processStateChange(); 
    } 

/*一個粗略的草圖,可能看起來像*/

使用shared_pointers管理生命週期,定義一些typedefs易於使用。

typedef std::shared_ptr<Ia> IaPtr; 
    typedef std::shared_ptr<Ib> IbPtr; 
    typedef std::shared_ptr<IA_impl> IAImplPtr; 
    typedef std::map<int /* or other datatype as required */ , IA_implPtr> ImplAPtrContainer; 

    // class-A may look like 
    class A : public IA 
    { 
    public: 
     void IaChanged(const IaPtr ptr_a); 
     void IbChanged(const IbPtr ptr_b); 
     void Init(); 
     void DeInit() { m_implAContainer.clear(); } 

    private: 
     int GetCurrentState(); 

    private: 
    ImplAPtrContainer m_implAContainer; 
    IAImplPtr m_pimplA; 
    IaPtr m_aPtr; 
    IbPtr m_bPtr; 
    IcPtr m_cPtr; 
    }; 

//初始化容器與所有可能的實現國家A級

void A::Init() 
    { 
     m_implAContainer.insert(/*state*/ 0, IAImplPtr(new A_implState0)); 
     m_implAContainer.insert(/*state*/ 1, IAImplPtr(new A_implState1)); 
     m_implAContainer.insert(/*state*/ X, IAImplPtr(new A_implStateX)); 
    } 

//確定根據A的當前狀態,B & C」當前狀態

int A::GetCurrentState() 
    { 
     // Have this method return A's state based on a b c, prefer enums over magic numbers 
     if(m_aPtr->GetState() == 0 && m_bPtr->GetState() == 0 && m_cPtr->GetState() == 0) 
      return 0; 
    } 
+0

嗨Arun,我需要一段時間來消化這個,但它似乎可以工作。至少,它會幫助我採取不同的方法。如果我解決了這個問題,你可以解決Factory方法中狀態模式的複雜性,並且可以使用許多版本的A? – awishformore 2013-02-28 03:15:52

+0

嗨Awishformore,如果你認爲工廠是一個矯枉過正的,看看新的編輯。它用容器代替工廠。容器是一種微不足道的工廠,充當查找。如果我們有不可改變的,確定的和小的一組狀態來處理,它們是可取的。希望這符合你的用例。 – Arun 2013-02-28 06:19:31

+0

我喜歡這種方法,但是困擾我的一件事情是需要爲每個狀態變化採用單獨的方法--Iachanged,Ibchanged等。將會有很多原子狀態,所以最好有一種廣義的方法做到這一點 - 但是,然後,我們再次只知道狀態的變化,而不是哪個狀態是 - 我想在這裏使用某種ID會做。你怎麼看? 我也想過GetCurrenState()方法 - 如何將hashmap實現爲查找表?這將能夠快速查找大量的複雜狀態,對嗎? – awishformore 2013-02-28 14:27:55