В какой ситуации мы должны принять государственную модель?
Мне поручили поддерживать проект, конечный автомат проекта был реализован с помощью 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 } };
Мне интересно, работает ли в этом случае шаблон состояния, чем указатель на функцию, или нет ... Использование только указателя функции также может улучшить читаемость (по сравнению с переключателем) и более просто. Шаблон состояния создаст несколько классов и будет более сложным, чем использование только указателя на функцию. В чем преимущество использования шаблона состояний?
Спасибо за ваше время!
State
). Добавьте несколько новых переходов или состояний, и вы увидите, что он очень быстро усложняется. Если состояние не поддерживает переход, оно должно вызывать исключение при вызове этого метода. Это симпатичнее твоего? - person Fuhrmanator   schedule 21.11.2015