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 未定义。

最后,根状态有一组它可以采用的状态,基于复合状态——遵循与以前相同的逻辑。

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

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

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

4

1 回答 1

0

一个快速的想法:

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

2) 使用 Pimpl idiom 实现 class-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 & Ic 状态变化通知(观察者模式的回调方法)。

3) 在原子接口 Ia、Ib 和 Ic 内部。定义公共 Register(IA&) 和私有 Notify() 方法。在界面 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 & c'当前状态判断A的当前状态

    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; 
    }
于 2013-02-28T02:19:53.330 回答