Design Patterns(二十) State

The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern’s interface.

前言

    状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。

状态模式

基本介绍:

1) 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换;
2) 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。

角色介绍:

1) Context 类为环境角色, 用于维护State实例,这个实例定义当前状态;
2) State 是抽象状态角色,定义一个接口封装与Context 的一个特点接口相关行为;
3) ConcreteState 具体的状态角色,每个子类实现一个与Context 的一个状态相关行为。

状态模式-UML图:





状态模式-实例图:


代码:

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/**
* @Auther: Arsenal
* @Date: 2020-03-21 13:28
* @Description: 状态模式
*/
public class StateDemo {
public static void main(String[] args) {
FlowContext context = new FlowContext();
context.setMessage("本人老王,因为十一家里有事情,所以要多请三天假,希望公司能够审核通过");
context.start(context);
}
}

/**
* 抽象状态类
*/
abstract class State {

public abstract void Handle(Context context);
}

/**
* 具体状态类A
*/
class ConcreteStateA extends State {

@Override
public void Handle(Context context) {
context.setState(new ConcreteStateB()); //设置A的下一个状态是B

}

}

/**
* 具体状态类B
*/
class ConcreteStateB extends State {

@Override
public void Handle(Context context) {
context.setState(new ConcreteStateA()); //设置B的下一个状态是A
}

}

/**
* Context类
*/
class Context {
State state;

public Context(State state) { //定义Context的初始状态
super();
this.state = state;
}

public State getState() {
return state;
}

public void setState(State state) {
this.state = state;
System.out.println("当前状态为" + state);
}

public void request() {
state.Handle(this); //对请求做处理并且指向下一个状态
}
}

/**
* 节点接口
*/
abstract class Node {
private static String name; //当前节点名称

//节点跳转
public abstract void nodeHandle(FlowContext context);

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

/**
* 领导节点
*/
class LeadNode extends Node {
@Override
public void nodeHandle(FlowContext context) {
//根据当前流程的状态,来控制流程的走向
//先判断流程是否结束
if (!context.isFlag()) {
System.out.println(context.getMessage()); //先读取申请的内容
if (context != null && 3 == context.getStatus()) { //只有出于已经申请的状态才又部门领导审核
//设置当前节点的名称
setName("张经理");
//加上审核意见
context.setMessage(context.getMessage() + getName() + "审核通过;");
//审核通过
context.setStatus(0); //审核通过并指向下一个节点
context.setNode(new HrNode());
context.getNode().nodeHandle(context);
}
} else {
System.err.println("流程已经结束");
}
}
}

/**
* hr节点
*/
class HrNode extends Node {

@Override
public void nodeHandle(FlowContext context) {
//先判断流程是否结束
if (!context.isFlag()) {
// 根据当前流程的状态,来控制流程的走向
if (context != null &&
0 == context.getStatus()) { //只有上一级审核通过后才能轮到HR审核
// 设置当前节点的名称
setName("HR李");
//读取上一级的审核内容并加上自己的意见
System.out.println(context.getMessage() + getName() + "审核通过");
// 审核通过
context.setStatus(0); //HR审核通过并指向下一个节点 ,如果没有下一个节点就把状态设置为终结
context.setFlag(true);
}
} else {
System.out.println("流程已经结束");
}
}
}

/**
* 流程控制
*/
class FlowContext {
private boolean flag; // 代表流程是否结束
/**
* 流程状态 0:通过 1:驳回 2.退回整改 3.已申请
*/
private int status;

private String message; // 消息
private Node node; // 节点信息

public boolean isFlag() {
return flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public int getStatus() {
return status;
}

public void setStatus(int status) {
this.status = status;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public Node getNode() {
return node;
}

public void setNode(Node node) {
this.node = node;
}

public static boolean start(FlowContext context) {
Node node = new LeadNode();
context.setNode(node); // 设置初始节点
context.setStatus(3); // 设置状态为申请中
context.getNode().nodeHandle(context); // 发起请求
// 最后要知道是否申请成功
//判断当前是最后一个节点并且审核通过,而且流程结束
if ("HR李".equals(node.getName()) && 0 == context.getStatus() && context.isFlag()) {
System.out.println("审核通过,流程结束");
return true;
} else {
System.out.println("审核未通过,流程已经结束");
return false;
}
}

public FlowContext() {
super();
}
}

总结

状态模式的注意事项和细节:

1) 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中;
2) 方便维护。将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,而且容易出错;
3) 符合“开闭原则”。容易增删状态;
4) 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度;
5) 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式。

延伸

    设计模式之状态模式
    状态模式总结-java版
    状态模式-菜鸟教程
    Design Patterns - State Pattern
    尚硅谷Java设计模式,韩顺平图解java设计模式

Content
  1. 1. 前言
  2. 2. 状态模式
  3. 3. 总结
  4. 4. 延伸