设计模式之禅——状态模式

引:状态(一个变量)变化了,然后就会出现不同的行为,这就是对状态模式最简单的理解,当然它还有很多约束。

定义

当一个对象内在状态改变时允许其他改变行为,这个对象看起来像改变其类。——行为类

状态模式的核心是封装,状态的变更引起了行为的变更,从外部开起来就好像这个对象对应的类发生了改变一样,状态模式的通用类图如下:

state

简单介绍类图中的3个角色

  1. State抽象状态角色:负责对象的状态的定义,并且封装环境角色以实现状态的切换。
  2. ConcreteState具体对象状态定义:每个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理。
  3. Context环境角色:定义客户端需要的接口,并且负责具体状态的切换。

下面是它的通用源码:

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
// 抽象状态角色
public abstract class State {
// 定义一个环境角色,提供子类访问
protected Context context;
// 设置环境角色
public void setContext(Context _context) {
this.context = _context;
}
// 行为1
public abstract void handle1();
// 行为2
public abstract void handle2();
}

// 具体状态角色
public alass concreteState1 extends State {
@Override
public void handle1() {
// 本状态下必须处理的逻辑
}
@Override
public void handle2() {
// 设置当前状态为state2
super.context.setCurrentState(Context.STATE2);
// 过度到state2状态,由Context实现
super.context.handle2();
}
}
public alass concreteState2 extends State {
@Override
public void handle2() {
// 本状态下必须处理的逻辑
}
@Override
public void handle1() {
// 设置当前状态为state1
super.context.setCurrentState(Context.STATE1);
// 过度到state1状态,由Context实现
super.context.handle1();
}
}

// 环境角色,它具有以下两个不成文的约束:
// 1. 把状态对象声明为静态变量,有几个状态对象就声明几个静态变量
// 2. 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式
public class Context {
// 定义状态
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
// 当前状态
private State currentState;
// 获得当前状态
public State getCurrentState() {
returncurrentState;
}
// 设置当前状态
public void setCurrentState(State currentState) {
this.currentState = currentState;
// 切换状态, 重要
this.currentState.setContext(this);
// 行为委托, 重要
public void handle1() {
this.currentState.handle1();
}
public void handle2() {
this.currentState.handle2();
}
}
}

// 场景类
public class Client {
public static void main(String[] args) {
// 定义环境角色
Context context = new Context();
// 初始化状态
context.setCurrentState(new ConcreteState1());
// 行为执行
context.handle1();
context.handle2();
}
}

应用

优点

  1. 结构清晰,提高系统的可维护性
  2. 遵循设计原则,很好体现了开闭原则和单一职责原则。
  3. 封装性非常好,将状态变化放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。

缺点

只有一个缺点,就是会随着状态的增多会出现类膨胀。

使用场景

  1. 行为随状态改变而改变的场景,如权限设计。
  2. 条件、分支判断语句的替代者。

注意事项

状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个。

最佳实践

状态模式其实经常会遇到,因为基本上都会遇到状态的切换。对于状态顺序的不同组成不同的状态变化线,我们可以使用建造者模式。

参考

  1. 《设计模式之禅》