Решение проблемы с предварительным объявлением с участием конечного автомата в C ++ - PullRequest
2 голосов
/ 15 июня 2010

Я недавно вернулся к разработке на C ++ после перерыва, и у меня есть вопрос относительно реализации State Design Pattern.Я использую ванильный шаблон, точно так же, как в книге GoF.

Моя проблема в том, что сам конечный автомат основан на некотором оборудовании, используемом как часть встроенной системы - так что дизайн исправлен и можетне может быть изменено.Это приводит к круговой зависимости между двумя состояниями (в частности), и я пытаюсь решить эту проблему.Вот упрощенный код (обратите внимание, что я попытался решить эту проблему с помощью заголовков, как обычно, но все еще имел проблемы - я их пропустил в этом фрагменте кода):

#include <iostream>
#include <memory>

using namespace std;

class Context
{
public:
    friend class State;

    Context() { }

private:
    State* m_state;
};

class State
{
public:
    State() { }

    virtual void Trigger1() = 0;
    virtual void Trigger2() = 0;
};

class LLT : public State
{
public:
    LLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};


class ALL : public State
{       
public: 
    ALL() { }
    void Trigger1() { new LLT(); }
    void Trigger2() { new DH();  }
};  

// DL needs to 'know' about DH.
class DL  : public State
{           
public:
    DL() { }
    void Trigger1() { new ALL(); }
    void Trigger2() { new DH();  }
};      

class HLT :  public State
{
public:
    HLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};

class AHL : public State
{
public:
    AHL() { }
    void Trigger1() { new DH();  }
    void Trigger2() { new HLT(); }
};

// DH needs to 'know' about DL.
class DH  : public State
{
public:
    DH () { }
    void Trigger1() { new AHL(); }
    void Trigger2() { new DL();  }
};


int main()
{
    auto_ptr<LLT> llt (new LLT);
    auto_ptr<ALL> all (new ALL);
    auto_ptr<DL>  dl (new DL);
    auto_ptr<HLT> hlt (new HLT);
    auto_ptr<AHL> ahl (new AHL);
    auto_ptr<DH>  dh (new DH);  

    return 0;
}

Проблема в основном заключается в том, что в StateШаблон, переходы между состояниями выполняются путем вызова метода ChangeState в классе Context, который вызывает конструктор следующего состояния.

Из-за циклической зависимости я не могу вызвать конструктор, поскольку невозможнопредварительно определите оба конструктора состояний «проблемы».

Я посмотрел эту статью и шаблонный метод, который казался идеальным решением - но это не так.Компиляция и мои знания шаблонов довольно ограничены ...

Другая идея, которая у меня возникла, состоит в том, чтобы попытаться представить класс Helper для подклассовых состояний посредством множественного наследования, чтобы увидеть, можно ли указатьконструктор базового класса и имеет ссылку на конструктор подкласса состояния.Но я думаю, что это было довольно амбициозно ...

Наконец, будет ли прямое внедрение шаблона проектирования фабричных методов лучшим способом решения всей проблемы?

1 Ответ

4 голосов
/ 15 июня 2010

Вы можете определить функции-члены вне определений классов, например,

class DL : public State
{
public:
    void Trigger2();
};

inline void DL::Trigger2() { new DH(); }

Определить функции-члены, которые полагаются на более поздние определения классов после определения этих классов.Ключевое слово inline необходимо только в том случае, если вы определяете функцию-член вне класса в файле заголовка.

Кроме того, почему вы просто используете new DH() в своих функциях;Вы пропускаете память повсюду!

...