В какой ситуации мы должны принять государственную модель?

В какой ситуации мы должны принять государственную модель?

Мне поручили поддерживать проект, конечный автомат проекта был реализован с помощью switch-case длиной более 2000 строк. Расширять функцию будет сложно, поэтому я бы хотел ее реорганизовать. Я изучаю паттерн государственного проектирования, но у меня есть некоторые недоразумения.

Простой пример:

1. Начальное состояние "WAIT", дождитесь, когда пользователь отправит команду загрузки.

2. Пока пользователь отправляет команду загрузки, перейдите в состояние «ПОДКЛЮЧИТЬ» и подключитесь к серверу.

3. После создания подключения перейти в состояние «ЗАГРУЗКА», продолжить прием данных с сервера.

4. Пока загрузка данных завершена, перейдите в раздел «ОТКЛЮЧИТЬ», отключите связь с сервером.

5. После отключения перейдите в состояние "WAIT", дождитесь, когда пользователь отправит команду загрузки.

Простое изображение конечного автомата

  • Метод 1. Прежде чем я исследую шаблон состояния, я думаю, что это тривиальный метод - обертка другого поведения состояния в разных функциях, использование массива указателей на функцию для указания каждой функции состояния и изменение состояния с помощью функции вызова.

    typedef enum {
        WAIT,
        CONNECT,
        DOWNLOADING,
        DISCONNECT
    }state;
    void (*statefunction[MAX_STATE])(void) = 
    {
        WAITState,
        CONNECTState,
        DOWNLOADINGState,
        DISCONNECTState
    };
    void WAITState(void)
    {
        //do wait behavior
        //while receive download command
        //statefunction[CONNECT]();
    }
    void CONNECTState(void)
    {
        //do connect behavior
        //while connect complete
        //statefunction[DOWNLOADING]();
    }
    void DOWNLOADINGState(void)
    {
        //do downloading behavior
        //while download complete
        //statefunction[DISCONNECT]();
    }
    void DISCONNECTState(void)
    {
        //do disconnect behavior
        //while disconnect complete
        //statefunction[WAIT]();
    }
    
  • Метод 2: шаблон состояния инкапсулирует различное состояние и его поведение в другом классе (объектно-ориентированный конечный автомат), использует полиморфизм для реализации различного поведения состояния и определяет общий интерфейс для всех конкретных состояний.

    class State
    {
    public:
         virtual void Handle(Context *pContext) = 0;
    };
    class Context
    {
    public:
        Context(State *pState) : m_pState(pState){}
    
        void Request()
        {
            if (m_pState)
            {             
                m_pState->Handle(this);           
            }
         }   
    private:
        State *m_pState;
    };
    class WAIT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do wait behavior
        }
    };
    class CONNECT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do connect behavior
        }
    };
    class DOWNLOADING : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do downloading behavior
        }
    };
    class DISCONNECT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do disconnect behavior
        }
    };
    

Мне интересно, работает ли в этом случае шаблон состояния, чем указатель на функцию, или нет ... Использование только указателя функции также может улучшить читаемость (по сравнению с переключателем) и более просто. Шаблон состояния создаст несколько классов и будет более сложным, чем использование только указателя на функцию. В чем преимущество использования шаблона состояний?

Спасибо за ваше время!


person Charlotte    schedule 19.11.2015    source источник
comment
Шаблон состояния с несколькими классами более полезен в языках, где вы не можете ссылаться на сами функции, например, Java (‹8), а скорее должны использовать объекты. Вы можете рассматривать вариант указателя функции как реализацию шаблона, а вариант с несколькими классами как шаблон сам по себе, который работает в обход языковых ограничений (как и большинство шаблонов).   -  person molbdnilo    schedule 19.11.2015
comment
Связанный, если не повторяющийся вопрос: stackoverflow.com/questions/4935806/   -  person Fuhrmanator    schedule 21.11.2015
comment
Расширять функцию будет сложно, поэтому я хотел бы ее реорганизовать - Вас просили расширить ее? Будут ли в расширении новые состояния, новые переходы или и то, и другое? В вашем примере показан только один переход (Handle), но у многих конечных автоматов их больше одного. Версия OO (метод 2) требует, чтобы все состояния реализовывали все переходы (поскольку они определены в классе State). Добавьте несколько новых переходов или состояний, и вы увидите, что он очень быстро усложняется. Если состояние не поддерживает переход, оно должно вызывать исключение при вызове этого метода. Это симпатичнее твоего?   -  person Fuhrmanator    schedule 21.11.2015


Ответы (1)


В чем преимущество использования шаблона состояний?

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

При этом сам узор имеет несколько преимуществ:

  1. Он ограничивает количество состояний, в которых может находиться программа, и, таким образом, - исключает неопределенные состояния,
  2. Это позволяет упростить расширение приложения путем добавления новых состояний вместо рефакторинга всего кода,
  3. С точки зрения компании это безопасно, даже когда несколько человек работают в одном классе,

Поскольку вы отметили вопрос как связанный с c ++ лучше всего учитывать то, что язык дает и требует. Хотя classes предлагает наследование, большое количество классов может значительно увеличить время компиляции. Следовательно, когда дело доходит до реализаций, если ваш конечный автомат большой, статический полиморфизм может оказаться правильным решением.

person Paweł Stawarz    schedule 19.11.2015