多层复杂状态机

时间:2013-02-27 23:21:54

标签: c++ design-patterns state-machine

我目前正在努力想出一个用于编码多层状态机的简洁设计,到目前为止,我还没有在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未定义。

最后,根状态可以根据复合状态采用一组状态 - 遵循与以前相同的逻辑。

到目前为止,我尝试了一种自上而下的方法,其中根将调用子状态,而子状态又会调用原子状态来更新它们,然后重新级联。

我还尝试了一种自下而上的方法,原子状态会更新并调用子状态,而子状态又会调用根状态。

在这两种情况下,单个子状态可能仅依赖于一个或多个原子状态的事实使得状态验证非常复杂,并且最终得到了不可接受的膨胀代码。我觉得我需要一种不同的方法,但我坚持目前的设计。如果有人有这种问题的经验并且可以提供一些灵感,我真的很感激。

1 个答案:

答案 0 :(得分:0)

一想法:

1)复合和原子状态之间的观察者模式(“a”,“b”,“c”作为观察者,“A”作为观察者,等等......)

2)使用Pimpl习语将A类实现分离界面&实现细节,因此在更改实现细节方面有更多的控制和更灵活的表现。

3)让A类具有某种工厂抽象来创建&管理每个独特状态“A”的专用实现对象。

4)因此,只要“A”观察到a,b,c的变化,Factory就会帮助检索相应的“A”实现状态并进行状态变化。 在“A”和“X”之间应用相同的方法。

更详细的布局:

1)定义所需的接口(通用或抽象类)IX,IA,Ia,Ib,Ic。

2)在接口IA中,定义public IaChanged(Ia *),IbChanged(Ib *)& IcChanged(Ic *)方法接收Ia,Ib和amp; Ic状态更改通知(Observer模式的回调方法)。

3)在原子界面Ia,Ib&内部。我知道了。定义公共注册(IA&)&私人通知()metods。 在Interface Ia中,

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

在接口Ib中,

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

等......

4)具有从各个接口派生的X,A,a,b,c。    X-> IX,A-> IA,a-> Ia,b-> Ib& c-> Ic,其中 - >代表“衍生”。

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)根据以下内容对A的每个不同状态进行一次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来管理生命周期,定义一些typedef以便于使用。

    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的所有可能实现状态初始化Container

    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和amp;确定A的当前状态。 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; 
    }