状态设计模式(State)

Posted by 余腾 on 2019-08-23
Estimated Reading Time 5 Minutes
Words 1.1k In Total
Viewed Times

什么是状态设计模式?

状态设计模式—> 行为型模式

基本介绍

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

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

状态设计模式应用实例



State

1
2
3
4
5
6
7
8
public abstract class State {

public abstract void deductMoney();

public abstract boolean lottery();

public abstract void dispensePrize();
}

NoLotteryState
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
//不可抽奖状态
public class NoLotteryState extends State {

LotteryActivity activity;

public NoLotteryState(LotteryActivity activity) {
this.activity = activity;
}

@Override
public void deductMoney() {
System.out.println("扣取成功,可以抽奖!");
//TODO 将状态改为 可以抽奖状态
activity.setState(activity.getCanLotteryState());
}

@Override
public boolean lottery() {
System.out.println("买过票,才可以抽奖!");
return false;
}

@Override
public void dispensePrize() {
System.out.println("不能发放奖品!");
}
}

CanLotteryState
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
//可以抽奖状态
public class CanLotteryState extends State {

LotteryActivity activity;

public CanLotteryState(LotteryActivity activity) {
this.activity = activity;
}

@Override
public void deductMoney() {
System.out.println("扣取成功,可以抽奖!");
}

@Override
public boolean lottery() {
System.out.println("正在抽奖,请稍等...");
Random r = new Random();
int num = r.nextInt(10);//TODO 10%中奖机会
if (num == 0) {
//TODO 改变活动状态为 发放奖品
activity.setState(activity.getDispenseState());
return true;
} else {
System.out.println("很遗憾没有中奖!");
//TODO 改变活动状态为 不能抽奖
activity.setState(activity.getNoLotteryState());
return false;
}
}

@Override
public void dispensePrize() {
System.out.println("没有中奖,不能发放奖品!");
}
}

DispenseState
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
//发放奖品状态
public class DispenseState extends State {

LotteryActivity activity;

public DispenseState(LotteryActivity activity) {
this.activity = activity;
}

@Override
public void deductMoney() {
System.out.println("不能扣钱!");
}

@Override
public boolean lottery() {
System.out.println("不能抽奖!");
return false;
}

@Override
public void dispensePrize() {
if (activity.getCount() > 0) {
System.out.println("===================> 恭喜中奖,发放奖品!");
//TODO 改变活动状态为 不能抽奖
activity.setState(activity.getNoLotteryState());
} else {
System.out.println("===================> 已中奖,但很遗憾,奖品发放完毕!");
activity.setState(activity.getDispensOutState());
// System.out.println("抽奖活动结束");//TODO 可以注释
// System.exit(0);//TODO 可以注释
}
}
}

DispenseOutState
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
//奖品发放完毕状态
public class DispenseOutState extends State {

LotteryActivity activity;

public DispenseOutState(LotteryActivity activity) {
this.activity = activity;
}

@Override
public void deductMoney() {
//System.out.println("奖品发放完毕,请下次参加!");
}

@Override
public boolean lottery() {
System.out.println("奖品发放完毕,请下次参加!");
return false;
}

@Override
public void dispensePrize() {
System.out.println("奖品发放完毕,请下次参加!");
}
}

LotteryActivity

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
public class LotteryActivity {

State state = null;//当前活动状态
int count = 0;//奖品数量

State canLotteryState = new CanLotteryState(this);
State noLotteryState = new NoLotteryState(this);

State dispenseState = new DispenseState(this);
State dispensOutState = new DispenseOutState(this);

public LotteryActivity(int count) {
this.state = getNoLotteryState();
this.count = count;
}

public void debuctMoney() {
state.deductMoney();
}

public void lottery() {
if (state.lottery()) {
state.dispensePrize();
}
}

public State getState() {
return state;
}

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

public int getCount() {
int curCount = count;
count--;
return curCount;
}

public void setCount(int count) {
this.count = count;
}


public State getNoLotteryState() {
return noLotteryState;
}

public void setNoLotteryState(State noLotteryState) {
this.noLotteryState = noLotteryState;
}

public State getCanLotteryState() {
return canLotteryState;
}

public void setCanLotteryState(State canLotteryState) {
this.canLotteryState = canLotteryState;
}

public State getDispenseState() {
return dispenseState;
}

public void setDispenseState(State dispenseState) {
this.dispenseState = dispenseState;
}

public State getDispensOutState() {
return dispensOutState;
}

public void setDispensOutState(State dispensOutState) {
this.dispensOutState = dispensOutState;
}
}

Client

1
2
3
4
5
6
7
8
9
10
11
public class Client {
public static void main(String[] args) {
LotteryActivity activity = new LotteryActivity(1);

for (int i = 1; i <= 20; i++) {
System.out.println("--------第" + i + "抽奖----------");
activity.debuctMoney();
activity.lottery();
}
}
}

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

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

感谢阅读


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !