15 Design Pattern_State Pattern_C Language Implementation

State mode

As the name suggests, the state mode is a mode used when implementing a state machine.

In embedded software development, we often encounter various state machines. Take the simplest example: a device has two states, as shown in the figure below:

Insert picture description here

Usually, the pseudo code we implement the state machine is as follows:

enum StateEnum {
    OpenState;
    CloseState;
};

enum OperatinEnum {
    LongPressButton; 
    ShortPressButton;    
}

int StateProcess(int currentState, int operation) 
{
    if (operation == LongPressButton) {
        if (currentState == OpenState) {
            // ...
            return CloseState;
        }
    } else if (operation == ShortPressButton) 
        if (currentState == CloseState) {
            // ...
            return OpenState;
        }
    }

    // 状态切换失败,保持当前状态
    return currentState; 
}

If we want to increase the sleep state, as shown below:

Insert picture description here

Then, we need to modify the code as follows (the line with "//–add" is the modified code this time):

enum StateEnum {
    OpenState;
    CloseState;
    SleepState; //--add
};

enum OperatinEnum {
    LongPressButton; 
    ShortPressButton; 
    FreeOver5Mins; //--add
}

int StateProcess(int currentState, int operation) 
{
    if (operation == LongPressButton) {
        if (currentState == OpenState) {
            // ...
            return CloseState;
        }
    } else if (operation == ShortPressButton) 
        if (currentState == CloseState) {
            // ...
            return OpenState;
        } else if (currentState == SleepState) { //--add
            // ...                               //--add
            return OpenState;                    //--add
        }
    } else if (operation == FreeOver5Mins) {     //--add
        if (currentState == OpenState) {         //--add
            // ...                               //--add
            return SleepState;                   //--add
        }
    }

    // 状态切换失败,保持当前状态
    return currentState; 
}

This is just a very, very simple state machine. But to be honest, at this level I have difficulty checking whether the code is implemented correctly. Therefore, the shortcomings of this implementation are obvious: 1) if-else is too many and too complicated, even a relatively simple state machine is difficult for people to understand at a glance; 2) obviously violates the principle of opening and closing.

So, according to the GOF state model, how should we achieve it? We should split the above code by "state" and treat each state as a separate class. When the sleep state is increased, we increase the sleep state class. The pseudo code is as follows:

enum StateEnum {
    OpenState;
    CloseState;
    SleepState;        //--add
};

enum OperatinEnum {
    LongPressButton; 
    ShortPressButton; 
    FreeOver5Mins;     //--add
}

// 定义State基类
struct State {
    struct State* (*LongPressButtonOperation)(); // LongPressButton的操作,返回next state
    struct State* (*ShortPressButtonOperation)();
    struct State* (*FreeOver5MinsOperation)();   //--add
}

// 定义OpenState类,继承State基类
struct OpenState {
    ... 根据本状态迁移的实际情况,重写基类中的方法
}

// 定义CloseState类,继承State基类
struct CloseState {
    ... 根据本状态迁移的实际情况,重写基类中的方法
}

// 定义SleepState类,继承State基类                   //--add
struct SleepState {                                  //--add
    ... 根据本状态迁移的实际情况,重写基类中的方法    //--add
}

// 定义StateProcessor(),驱动状态迁移
StateProcessor() {
    ...
}

Here I just wrote the pseudo-code of the state mode, not going to expand it in detail. The main reason is that I personally feel that this implementation method is obviously better than the previous method. But I still feel that implementing a state machine like this is not very good. Because this method mainly solves the problem of increasing the state, but does not solve the problem of increasing the operation, and then in practice, once the state machine changes, most scenarios have changes in state and operation. As for the previous example, increasing the sleep state will also increase the FreeOver5Mins operation, and the open state will also increase the FreeOver5Mins operation.

Anyway, I haven't seen how the state machine does not increase the operation when the state is increased. Therefore, I usually implement the state machine in another way. I will treat each current state-operation-next state as a class, and then use the StateProcessor to drive the state transition.

enum StateEnum {
    OpenState;
    CloseState;
    SleepState;        //--add
};

enum OperatinEnum {
    LongPressButton; 
    ShortPressButton; 
    FreeOver5Mins;     //--add
}

// 定义State--Operation基类
struct State {
    int currentState;
    int operation;
    int (*Operation)(); 
    int nextState;
}

struct State g_fsm[] = {
    { OpenState,
      LongPressButton,
      xxxOperation(), // 根据本状态迁移的实际情况,重写基类中的方法
      CloseState
    },
    { CloseState,
      ShortPressButton,
      xxxOperation(), // 根据本状态迁移的实际情况,重写基类中的方法
      OpenState,
    },
    { OpenState,       //--add
      FreeOver5Mins,   //--add
      xxxOperation(),  //--add
      SleepState,      //--add
    },
    { SleepState,       //--add
      ShortPressButton, //--add
      xxxOperation(),   //--add
      OpenState,        //--add
    },
};

// 定义StateProcessor(),驱动状态迁移
int StateProcessor(int currentState, int operation) {
    for (i = 0; i < g_fsm[]的成员数; i++) {
        if (currentState == g_fsm[i].currentState) && (operation == g_fsm[i].operation) {
            g_fsm[i].xxxOperation(); 
            return g_fsm[i].nextState;
        }
    }

    // 状态切换失败,保持当前状态
    return currentState; 
}

I think this method is different from GOF's state mode, but I personally think this method is more perfect.

Guess you like

Origin blog.csdn.net/weixin_46826913/article/details/108190516