设计模式-状态模式

状态模式(State Pattern): 允许一个对象在其内部状态改变时改变它的行为. 对象看起来似乎修改了它的类.

设计模式-概述

状态对于一个对象来说, 是一个很平常的属性, 比如一个任务对象, 它有未开始,已开始,进行中,已完成等等各种状态, 为了针对不同的状态变更, 来做不同的处理, 如果不用设计模式的写法, 将会产生大量的 if-else, 一旦新需求到来, 需要新的状态, 就会越写越多, 导致代码可读性和可维护性降低. 使用状态模式可以解决这个问题, 它能解决复杂对象的状态切换以及不同状态下的行为的封装问题

结构

状态模式引入了抽象状态类和具体状态类, 包含了3种角色.

  1. 环境类(Context): 是一个拥有多个状态的对象. 环境会随着状态不同, 而有不同的行为.
  2. 状态抽象类(State): 定义了一个接口, 用来封装某个状态下环境的行为.
  3. 具体状态类(ConcreteState): 实现了环境的某个状态下的具体的行为.

state-1.png

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
@startuml state-1
!include common.cuml

Interface(State,"抽象状态") {
+ handle() : void
}

Class(ConcreteStateA,"具体状态A") {
+ handle() : void
}

Class(ConcreteStateB,"具体状态B") {
+ handle() : void
}

Class(Context,"环境") {
- state : State
+ request() : void
+ setState(State state) : void
}

note as N1
public void request() {
// todo 自己的处理逻辑a
state.handle();
// todo 自己的处理逻辑b
}
end note

N1 ... Context

ConcreteStateA --|> State
ConcreteStateB --|> State

State <--o Context

@enduml

代码实现

  1. 定义三种状态, 并且实现内部行为
  2. 客户端调用行为方法, 无需关系当前处于何种状态, 具体实现由状态类管理
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
package com.yuda.desigmode;

public class Main3 {
public static void main(String[] args) {
Context context = new Context();
context.setState(new ConcreteStateA());
context.request();
System.out.println("切换状态");
context.setState(new ConcreteStateB());
context.request();
System.out.println("再次切换状态");
context.setState(new ConcreteStateC());
context.request();
}
}

interface State {
void handle();
}

class ConcreteStateA implements State {

@Override
public void handle() {
System.out.println("ConcreteStateA.handle");
}
}

class ConcreteStateB implements State {

@Override
public void handle() {
System.out.println("ConcreteStateB.handle");
}
}

class ConcreteStateC implements State {

@Override
public void handle() {
System.out.println("ConcreteStateC.handle");
}
}

class Context {
private State state;

public void request() {
state.handle();
}

public void setState(State state) {
this.state = state;
}
}

结果为:

1
2
3
4
5
ConcreteStateA.handle
切换状态
ConcreteStateB.handle
再次切换状态
ConcreteStateC.handle

有新需求如果需要一个新状态, 只需要新增一个实现就可以了, 不用修改状态的实现.

使用场景

  1. 对象的行为依赖于它的状态, 切换状态后, 行为也会有变化时.
  2. 某个对象有大量的状态, 并且随着版本更新换代, 状态会更多时.(即如果发现if-else太多, 可以考虑用状态模式)

具体应用

todo 还没见过用, 见到再补