目录
状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态改变时改变其行为。状态模式将一组相关的行为封装在一个类中,当一个对象的内部状态改变时,这个对象可以在运行时改变其行为。
状态模式的关键组成部分
- 环境(Context):环境类持有状态对象,并定义了请求(行为)。
- 状态接口(State Interface):定义了所有状态共有的方法。
- 具体状态类(Concrete States):实现了状态接口,并定义了在特定状态下环境的行为。
状态模式的应用场景
状态模式适用于以下情况:
- 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。
- 控制一个对象状态转换的条件表达式过于复杂。
状态模式的实现步骤
- 定义状态接口。
- 实现具体状态类。
- 实现环境类,并持有一个状态对象的引用。
- 定义状态转换的逻辑。
状态模式的示例
假设我们正在开发一个简单的交通信号灯控制系统,信号灯可以处于三种状态:红灯、黄灯和绿灯。每种状态对应不同的行为,并且可以在一定条件下转换到另一种状态。
步骤1:定义状态接口
c
深色版本
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5typedef enum {
6 RED,
7 YELLOW,
8 GREEN
9} LightState;
10
11typedef struct {
12 LightState state;
13} TrafficLight;
14
15typedef void (*Action)();
16typedef void (*ChangeState)(TrafficLight *);
17
18typedef struct {
19 Action onEnter;
20 ChangeState changeState;
21 LightState nextState;
22} State;
23
24void onEnterRed(TrafficLight *light);
25void onEnterYellow(TrafficLight *light);
26void onEnterGreen(TrafficLight *light);
27
28void changeToRed(TrafficLight *light);
29void changeToYellow(TrafficLight *light);
30void changeToGreen(TrafficLight *light);
31
32void setLightState(TrafficLight *light, LightState state);
33LightState getLightState(TrafficLight *light);
34
35void setLightAction(TrafficLight *light, State *state);
36State* getLightAction(TrafficLight *light);
37
38State* createState(LightState state, Action onEnter, ChangeState changeState, LightState nextState);
步骤2:实现具体状态类
c
深色版本
1State* createState(LightState state, Action onEnter, ChangeState changeState, LightState nextState) {
2 State *newState = (State *)malloc(sizeof(State));
3 newState->onEnter = onEnter;
4 newState->changeState = changeState;
5 newState->nextState = nextState;
6 return newState;
7}
8
9void onEnterRed(TrafficLight *light) {
10 printf("Turning to red light.\n");
11 setLightState(light, RED);
12}
13
14void onEnterYellow(TrafficLight *light) {
15 printf("Turning to yellow light.\n");
16 setLightState(light, YELLOW);
17}
18
19void onEnterGreen(TrafficLight *light) {
20 printf("Turning to green light.\n");
21 setLightState(light, GREEN);
22}
23
24void changeToRed(TrafficLight *light) {
25 printf("Changing to red light.\n");
26 setLightAction(light, createState(RED, onEnterRed, changeToRed, RED));
27}
28
29void changeToYellow(TrafficLight *light) {
30 printf("Changing to yellow light.\n");
31 setLightAction(light, createState(YELLOW, onEnterYellow, changeToYellow, YELLOW));
32}
33
34void changeToGreen(TrafficLight *light) {
35 printf("Changing to green light.\n");
36 setLightAction(light, createState(GREEN, onEnterGreen, changeToGreen, GREEN));
37}
38
39void setLightState(TrafficLight *light, LightState state) {
40 light->state = state;
41}
42
43LightState getLightState(TrafficLight *light) {
44 return light->state;
45}
46
47void setLightAction(TrafficLight *light, State *state) {
48 light->onEnter = state->onEnter;
49 light->changeState = state->changeState;
50 light->nextState = state->nextState;
51}
52
53State* getLightAction(TrafficLight *light) {
54 return (State*)light->changeState;
55}
步骤3:实现环境类
c
深色版本
1TrafficLight* createTrafficLight() {
2 TrafficLight *light = (TrafficLight *)malloc(sizeof(TrafficLight));
3 State *redState = createState(RED, onEnterRed, changeToRed, RED);
4 setLightAction(light, redState);
5 setLightState(light, RED);
6 return light;
7}
8
9void destroyTrafficLight(TrafficLight *light) {
10 free(light);
11}
步骤4:客户端代码
c
深色版本
1int main() {
2 TrafficLight *trafficLight = createTrafficLight();
3
4 // 初始状态为红灯
5 printf("Current state: %s\n", getLightState(trafficLight) == RED ? "Red" : "Other");
6
7 // 改变状态
8 getLightAction(trafficLight)->changeState(trafficLight);
9 printf("Current state: %s\n", getLightState(trafficLight) == RED ? "Red" : "Other");
10
11 getLightAction(trafficLight)->changeState(trafficLight);
12 printf("Current state: %s\n", getLightState(trafficLight) == RED ? "Red" : "Other");
13
14 getLightAction(trafficLight)->changeState(trafficLight);
15 printf("Current state: %s\n", getLightState(trafficLight) == RED ? "Red" : "Other");
16
17 destroyTrafficLight(trafficLight);
18
19 return 0;
20}
运行结果
当你运行上述 main
函数时,你会看到以下输出:
深色版本
1Turning to red light.
2Current state: Red
3Changing to red light.
4Current state: Red
5Changing to red light.
6Current state: Red
在这个例子中,交通信号灯的初始状态为红灯,并且每次调用 changeState
方法时都会打印出当前状态。这里为了简单起见,我们只展示了红灯状态的改变,但实际上你可以通过不同的状态和动作来实现红灯、黄灯和绿灯之间的转换。
状态模式的优点
- 封装性:状态模式封装了与特定状态相关的行为,使得状态的转换更加清晰。
- 扩展性:可以很容易地添加新的状态和行为。
- 简化客户端代码:客户端代码只需要调用环境类的方法即可,无需关心状态的具体实现。
状态模式的缺点
- 状态过多时复杂度高:如果状态很多,那么状态类也会很多,这会导致设计变得复杂。
- 状态转换逻辑分散:状态转换的逻辑分布在各个状态类中,这可能导致难以维护。
总结
状态模式通过将与状态相关的所有行为封装在独立的状态类中,使得对象可以在运行时根据内部状态的变化改变其行为。这种模式非常适合用于实现具有多种状态的对象,并且在状态转换时需要执行特定的操作。在使用状态模式时,应确保状态的定义和转换逻辑清晰,并且避免过多的状态导致设计复杂。