状态模式(State Pattern)详解

什么是状态模式

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。状态模式将状态的行为封装在对应的状态类中,使得状态的转换更加清晰和可维护。

状态模式解决的问题

状态模式主要解决以下问题:

  1. 消除状态判断:避免使用大量的 if-elseswitch-case 语句来处理不同状态的行为
  2. 状态转换管理:将状态转换的逻辑集中管理,避免状态转换分散在代码各处
  3. 状态行为封装:将每个状态的行为封装在对应的状态类中,职责单一
  4. 状态的动态切换:允许在运行时动态地切换对象的状态
  5. 代码复用:通过状态类复用不同状态的行为

状态模式的好处

  1. 代码清晰:消除了复杂的条件判断,代码结构清晰
  2. 可维护性:每个状态的行为都在自己的类中,易于维护
  3. 可扩展性:可以通过添加新的状态类来扩展功能
  4. 状态转换明确:状态转换的逻辑更加明确和集中
  5. 符合设计原则:遵循开闭原则和单一职责原则

状态模式的结构

状态模式包含以下几个角色:

  1. 状态接口(State):定义所有状态的公共接口
  2. 具体状态(Concrete State):实现状态接口的具体状态类
  3. 上下文(Context):持有一个状态对象的引用,使用状态对象处理请求

各语言实现

C++ 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <memory>

// 前向声明
class Context;

// 状态接口
class State {
public:
virtual ~State() = default;
virtual void handle(Context& context) = 0;
virtual std::string getName() const = 0;
};

// 上下文
class Context {
private:
std::unique_ptr<State> currentState;

public:
Context(std::unique_ptr<State> state)
: currentState(std::move(state)) {}

void setState(std::unique_ptr<State> state) {
currentState = std::move(state);
std::cout << "状态切换到:" << currentState->getName() << std::endl;
}

void request() {
currentState->handle(*this);
}
};

// 具体状态:就绪状态
class ReadyState : public State {
public:
void handle(Context& context) override;
std::string getName() const override {
return "就绪状态";
}
};

// 具体状态:运行状态
class RunningState : public State {
public:
void handle(Context& context) override;
std::string getName() const override {
return "运行状态";
}
};

// 具体状态:暂停状态
class PausedState : public State {
public:
void handle(Context& context) override;
std::string getName() const override {
return "暂停状态";
}
};

// 具体状态:停止状态
class StoppedState : public State {
public:
void handle(Context& context) override;
std::string getName() const override {
return "停止状态";
}
};

// 实现状态转换逻辑
void ReadyState::handle(Context& context) {
std::cout << "当前是就绪状态,开始运行..." << std::endl;
context.setState(std::make_unique<RunningState>());
}

void RunningState::handle(Context& context) {
std::cout << "当前是运行状态,暂停运行..." << std::endl;
context.setState(std::make_unique<PausedState>());
}

void PausedState::handle(Context& context) {
std::cout << "当前是暂停状态,继续运行..." << std::endl;
context.setState(std::make_unique<RunningState>());
}

void StoppedState::handle(Context& context) {
std::cout << "当前是停止状态,准备就绪..." << std::endl;
context.setState(std::make_unique<ReadyState>());
}

// 客户端代码
int main() {
Context context(std::make_unique<StoppedState>());

std::cout << "第一次请求:" << std::endl;
context.request();

std::cout << "\n第二次请求:" << std::endl;
context.request();

std::cout << "\n第三次请求:" << std::endl;
context.request();

std::cout << "\n第四次请求:" << std::endl;
context.request();

return 0;
}

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// 状态接口
interface State {
void handle(Context context);
String getName();
}

// 上下文
class Context {
private State currentState;

public Context(State state) {
this.currentState = state;
}

public void setState(State state) {
this.currentState = state;
System.out.println("状态切换到:" + currentState.getName());
}

public void request() {
currentState.handle(this);
}
}

// 具体状态:就绪状态
class ReadyState implements State {
@Override
public void handle(Context context) {
System.out.println("当前是就绪状态,开始运行...");
context.setState(new RunningState());
}

@Override
public String getName() {
return "就绪状态";
}
}

// 具体状态:运行状态
class RunningState implements State {
@Override
public void handle(Context context) {
System.out.println("当前是运行状态,暂停运行...");
context.setState(new PausedState());
}

@Override
public String getName() {
return "运行状态";
}
}

// 具体状态:暂停状态
class PausedState implements State {
@Override
public void handle(Context context) {
System.out.println("当前是暂停状态,继续运行...");
context.setState(new RunningState());
}

@Override
public String getName() {
return "暂停状态";
}
}

// 具体状态:停止状态
class StoppedState implements State {
@Override
public void handle(Context context) {
System.out.println("当前是停止状态,准备就绪...");
context.setState(new ReadyState());
}

@Override
public String getName() {
return "停止状态";
}
}

// 客户端代码
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context(new StoppedState());

System.out.println("第一次请求:");
context.request();

System.out.println("\n第二次请求:");
context.request();

System.out.println("\n第三次请求:");
context.request();

System.out.println("\n第四次请求:");
context.request();
}
}

Python 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 状态接口
from abc import ABC, abstractmethod

class State(ABC):
@abstractmethod
def handle(self, context):
pass

@abstractmethod
def get_name(self):
pass

# 上下文
class Context:
def __init__(self, state):
self.current_state = state

def set_state(self, state):
self.current_state = state
print(f"状态切换到:{self.current_state.get_name()}")

def request(self):
self.current_state.handle(self)

# 具体状态:就绪状态
class ReadyState(State):
def handle(self, context):
print("当前是就绪状态,开始运行...")
context.set_state(RunningState())

def get_name(self):
return "就绪状态"

# 具体状态:运行状态
class RunningState(State):
def handle(self, context):
print("当前是运行状态,暂停运行...")
context.set_state(PausedState())

def get_name(self):
return "运行状态"

# 具体状态:暂停状态
class PausedState(State):
def handle(self, context):
print("当前是暂停状态,继续运行...")
context.set_state(RunningState())

def get_name(self):
return "暂停状态"

# 具体状态:停止状态
class StoppedState(State):
def handle(self, context):
print("当前是停止状态,准备就绪...")
context.set_state(ReadyState())

def get_name(self):
return "停止状态"

# 客户端代码
if __name__ == "__main__":
context = Context(StoppedState())

print("第一次请求:")
context.request()

print("\n第二次请求:")
context.request()

print("\n第三次请求:")
context.request()

print("\n第四次请求:")
context.request()

C# 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using System;

// 状态接口
interface IState {
void Handle(Context context);
string GetName();
}

// 上下文
class Context {
private IState currentState;

public Context(IState state) {
this.currentState = state;
}

public void SetState(IState state) {
this.currentState = state;
Console.WriteLine($"状态切换到:{currentState.GetName()}");
}

public void Request() {
currentState.Handle(this);
}
}

// 具体状态:就绪状态
class ReadyState : IState {
public void Handle(Context context) {
Console.WriteLine("当前是就绪状态,开始运行...");
context.SetState(new RunningState());
}

public string GetName() {
return "就绪状态";
}
}

// 具体状态:运行状态
class RunningState : IState {
public void Handle(Context context) {
Console.WriteLine("当前是运行状态,暂停运行...");
context.SetState(new PausedState());
}

public string GetName() {
return "运行状态";
}
}

// 具体状态:暂停状态
class PausedState : IState {
public void Handle(Context context) {
Console.WriteLine("当前是暂停状态,继续运行...");
context.SetState(new RunningState());
}

public string GetName() {
return "暂停状态";
}
}

// 具体状态:停止状态
class StoppedState : IState {
public void Handle(Context context) {
Console.WriteLine("当前是停止状态,准备就绪...");
context.SetState(new ReadyState());
}

public string GetName() {
return "停止状态";
}
}

// 客户端代码
class Program {
static void Main(string[] args) {
Context context = new Context(new StoppedState());

Console.WriteLine("第一次请求:");
context.Request();

Console.WriteLine("\n第二次请求:");
context.Request();

Console.WriteLine("\n第三次请求:");
context.Request();

Console.WriteLine("\n第四次请求:");
context.Request();
}
}

状态模式的适用场景

状态模式适用于以下情况:

  1. 对象有多个状态:当一个对象有多个状态,并且状态之间需要相互转换时
  2. 状态影响行为:当对象的行为随着状态的改变而改变时
  3. 消除条件判断:当使用大量的条件语句来处理不同状态的行为时
  4. 状态转换复杂:当状态转换的逻辑比较复杂时
  5. 状态需要扩展:当需要频繁地添加新的状态时

实际应用场景

  1. 订单系统:订单的不同状态(待支付、已支付、待发货、已发货、已完成、已取消等)
  2. 工作流系统:流程的不同状态(待处理、处理中、已完成、已拒绝等)
  3. 游戏开发:游戏角色的不同状态( idle、running、jumping、attacking 等)
  4. 网络连接:网络连接的不同状态(断开、连接中、已连接、错误等)
  5. 文档编辑器:文档的不同状态(编辑中、已保存、已锁定等)
  6. 电梯系统:电梯的不同状态(停止、上升、下降、开门、关门等)

状态模式与策略模式的区别

虽然状态模式和策略模式的结构相似,但它们的意图不同:

  1. 状态模式:关注对象状态的变化和状态之间的转换
  2. 策略模式:关注算法的选择和替换
  3. 状态转换:状态模式中,状态的转换通常由状态类自己控制;策略模式中,策略的选择由客户端控制
  4. 状态数量:状态模式中,状态的数量通常是固定的;策略模式中,策略的数量可以根据需要添加

注意事项

  1. 状态数量:如果状态数量过多,可能会导致类的数量激增
  2. 状态转换:状态转换的逻辑需要仔细设计,避免出现循环转换
  3. 上下文与状态的关系:上下文和状态之间可能存在循环引用,需要注意内存管理
  4. 性能考虑:如果状态切换非常频繁,可能会有性能开销
  5. 状态的持久化:如果需要持久化对象的状态,需要考虑状态的序列化

总结

状态模式是一种非常实用的设计模式,它通过将状态的行为封装在对应的状态类中,使得状态的管理更加清晰和可维护。状态模式不仅可以消除复杂的条件判断,还可以提高代码的可扩展性和可维护性。在实际开发中,当遇到对象有多个状态且状态之间需要相互转换的场景时,状态模式是一个很好的解决方案。