设计模式之状态模式

释放双眼,带上耳机,听听看~!

0x01.定义与类型

  • 定义:允许一个对象在内部状态改变时,改变它的行为。
  • 类型:行为型
  • UML类图,这个基本实现类似电灯开关那种(0,1)的状态切换。

设计模式之状态模式

  • 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
1/**
2 * 状态上下文
3 * 维护一个state实例,这个为实体当前的状态
4 */
5public class Context {
6
7    /**
8     * 当前的状态
9     */
10    private State state;
11
12    /**
13     * 构造函数
14     * @param state
15     */
16    public Context(State state) {
17        this.state = state;
18    }
19
20    /**
21     * 请求状态
22     */
23    public void request() {
24        state.handler(this);
25    }
26
27    //--set get
28
29    public State getState() {
30        return state;
31    }
32
33    public void setState(State state) {
34        this.state = state;
35    }
36}
37
38/**
39 * 状态接口
40 */
41public interface State {
42
43    void handler(Context context);
44
45}
46
47/**
48 * 具体的状态
49 */
50public class ConcreteStateA implements State {
51    @Override
52    public void handler(Context context) {
53        System.out.println("this is state A.");
54        context.setState(new ConcreteStateB());
55    }
56}
57
58/**
59 * 具体的状态
60 */
61public class ConcreteStateB implements State {
62    @Override
63    public void handler(Context context) {
64        System.out.println("this is state B.");
65        context.setState(new ConcreteStateA());
66    }
67}
68
69
  • 测试与应用


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1/**
2 * 测试与应用
3 */
4public class Test {
5
6    public static void main(String[] args) {
7        //创建状态上下文
8        Context context = new Context(new ConcreteStateA());
9
10        //切换状态, 这个有点类似电灯的开关状态
11        context.request();
12        context.request();
13        context.request();
14        context.request();
15        context.request();
16    }
17}
18
19
  • 输入日志


1
2
3
4
5
6
7
1this is state A.
2this is state B.
3this is state A.
4this is state B.
5this is state A.
6
7
  • 状态模式中的角色介绍

  • 上下文环境(Context):它定义了客户端程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理。

    • 抽象状态(State):定义一个接口以封装使用上下文环境的一个特定状态的相关的行为。
    • 具体状态(Concrete State):实现抽象状态定义的接口。

0x02.适用场景

  • 一个对象存在多个状态(不同状态下行为不同),且状态可相互转换。
  • 电商订单状态扭转。
  • 主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的逻辑判断简单化。

0x03.优缺点

1.优点

  • 状态模式将与特定状态相关的行为局部化,把不同的状态隔离。
  • 把各种状态的转换逻辑,分布到State的子类中,减少相互间的依赖。
  • 所有状态相关的代码都在子类中,所以增加新的状态非常简单。

2.缺点

  • 状态多的业务场景导致类数目增加,系统变复杂。

0x04.状态模式样例

假设一个视频的播放有播放中、暂停、快进和停止等等状态,使用状态模式实现这个功能。

  • 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
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
1/**
2 * 课程状态上下文
3 */
4public class CourseVideoContext {
5
6    //当前状态
7    private CourseVideoState courseVideoState;
8
9    //播放
10    public final static PlayState PLAY_STATE = new PlayState();
11
12    //停止
13    public final static StopState STOP_STATE = new StopState();
14
15    //快进
16    public final static SpeedState SPEED_STATE = new SpeedState();
17
18    //暂停
19    public final static PauseState PAUSE_STATE = new PauseState();
20
21    public CourseVideoState getCourseVideoState() {
22        return courseVideoState;
23    }
24
25    public void setCourseVideoState(CourseVideoState courseVideoState) {
26        this.courseVideoState = courseVideoState;
27        this.courseVideoState.setCourseVideoContext(this);
28    }
29
30    public void play() {
31        this.courseVideoState.play();
32    }
33
34    public void speed() {
35        this.courseVideoState.speed();
36    }
37
38    public void pause() {
39        this.courseVideoState.pause();
40    }
41
42    public void stop() {
43        this.courseVideoState.stop();
44    }
45}
46
47/**
48 * 状态
49 */
50public abstract class CourseVideoState {
51
52    protected CourseVideoContext courseVideoContext;
53
54    public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
55        this.courseVideoContext = courseVideoContext;
56    }
57
58    public abstract void play();
59
60    public abstract void speed();
61
62    public abstract void pause();
63
64    public abstract void stop();
65}
66
67/**
68 * 暂停状态
69 */
70public class PauseState extends CourseVideoState {
71
72    @Override
73    public void play() {
74        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
75    }
76
77    @Override
78    public void speed() {
79        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
80    }
81
82    @Override
83    public void pause() {
84        System.out.println("暂停播放视频");
85    }
86
87    @Override
88    public void stop() {
89        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
90    }
91}
92
93/**
94 * 播放状态
95 */
96public class PlayState extends CourseVideoState {
97    @Override
98    public void play() {
99        System.out.println("正常播放视频的状态");
100    }
101
102    @Override
103    public void speed() {
104        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
105    }
106
107    @Override
108    public void pause() {
109        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
110    }
111
112    @Override
113    public void stop() {
114        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
115    }
116}
117
118/**
119 * 加速状态
120 */
121public class SpeedState extends CourseVideoState  {
122    @Override
123    public void play() {
124        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
125    }
126
127    @Override
128    public void speed() {
129        System.out.println("快进播放视频");
130    }
131
132    @Override
133    public void pause() {
134        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
135    }
136
137    @Override
138    public void stop() {
139        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
140    }
141}
142
143/**
144 * 停止状态
145 */
146public class StopState extends CourseVideoState  {
147    @Override
148    public void play() {
149        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
150    }
151
152    @Override
153    public void speed() {
154        System.out.println("ERROR 停止状态不能快进!!!");
155    }
156
157    @Override
158    public void pause() {
159        System.out.println("ERROR 停止状态不能暂停!!!");
160    }
161
162    @Override
163    public void stop() {
164        System.out.println("停止播放视频。");
165    }
166}
167
168
  • 测试与应用


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
1/**
2 * 测试与应用
3 */
4public class Test {
5
6    public static void main(String[] args) {
7        //状态上下文
8        CourseVideoContext courseVideoContext = new CourseVideoContext();
9
10        //状态
11        courseVideoContext.setCourseVideoState(new PlayState());
12        System.out.println("当前状态:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
13
14        courseVideoContext.pause();
15        System.out.println("当前状态:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
16
17        courseVideoContext.speed();
18        System.out.println("当前状态:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
19
20        courseVideoContext.stop();
21        System.out.println("当前状态:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
22
23        courseVideoContext.speed();
24
25    }
26}
27
28
  • 输入结果


1
2
3
4
5
6
7
1当前状态:PlayState
2当前状态:PauseState
3当前状态:SpeedState
4当前状态:StopState
5ERROR 停止状态不能快进!!!
6
7
  • UML类图

设计模式之状态模式

0x05.相关的设计模式

  • 状态模式和享元模式

0x06.源码中的状态模式

  • javax.Lifecycle

0x07.源码地址

0x08.推荐阅读

给TA打赏
共{{data.count}}人
人已打赏
安全运维

Step into Redis- 02 - set ,get & incr ,decr

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索