状态模式
欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。
# 简介
状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。
当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。
- Context 类为环境角色,用于维护 State 实例,这个实例定义当前状态。
- State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为。
- ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为。
# 代码示例
例如:用户扣积分抽奖,用户每次抽奖扣除 50 积分,如果账户积分大于 50 则可以抽奖,如果小于就不能抽奖,如果中奖就发放奖品,如果奖品发放完毕则无法领取。
/**
* 状态接口
*/
public interface State {
/**
* 扣除积分
*/
void deductPoints(int points);
/**
* 是否抽中奖品
*/
boolean raffle();
/**
* 发放奖品
*/
void dispensePrize();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 不能抽奖的状态
*/
@AllArgsConstructor
public class NoRaffleState implements State {
private final RaffleActivity activity;
// 扣除积分,然后把状态设置为可以抽奖
@Override
public void deductPoints(int currentPoints) {
if (currentPoints >= 50) {
System.out.println("积分充足,您可以抽奖了");
activity.setState(activity.getCanRaffleState());
} else {
System.out.println("积分不足,不能抽奖");
}
}
// 在当前状态下不能抽奖
@Override
public boolean raffle() {
System.out.println("扣了积分才能抽奖!");
return false;
}
// 在当前状态下不会发放奖品
@Override
public void dispensePrize() {
System.out.println("没有奖品发放!");
}
}
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
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
/**
* 发放奖品的状态
*/
@AllArgsConstructor
public class DispenseState implements State {
private final RaffleActivity activity;
/**
* 扣除积分
*/
@Override
public void deductPoints(int points) {
System.out.println("不能扣除积分!");
}
/**
* 是否抽中奖品
*/
@Override
public boolean raffle() {
System.out.println("不能抽奖!");
return false;
}
/**
* 发放奖品 如果奖品还有剩余,则将状态设置为不能抽奖,否则设置为奖品领完
*/
@Override
public void dispensePrize() {
if (activity.getCount() > 0) {
System.out.println("恭喜中奖!");
activity.setState(activity.getNoRaffleState());
} else {
System.out.println("很遗憾,奖品发送完了!");
activity.setState(activity.getDispenseOutState());
}
}
}
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
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
/**
* 奖品发放完毕状态 说明,当我们activity 改变成 DispenseOutState, 抽奖活动结束
*/
@AllArgsConstructor
public class DispenseOutState implements State {
private final RaffleActivity activity;
// 在当前状态下不能扣除积分
@Override
public void deductPoints(int points) {
System.out.println("奖品发送完了,不能再扣除积分了!");
}
// 在当前状态下不能抽奖
@Override
public boolean raffle() {
System.out.println("奖品发送完了,不能再抽奖了!");
return false;
}
// 在当前状态下不能发放奖品
@Override
public void dispensePrize() {
System.out.println("奖品发送完了,不能再发放奖品了!");
}
}
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
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
/**
* 可以抽奖的状态
*/
@AllArgsConstructor
public class CanRaffleState implements State {
private final RaffleActivity activity;
/**
* 扣除积分,然后把状态设置为不能抽奖
*/
@Override
public void deductPoints(int currentPoints) {
if (currentPoints >= 50) {
System.out.println("扣除50积分,您可以继续抽奖");
activity.setPoints(currentPoints - 50);
// 切换状态
activity.setState(activity.getCanRaffleState());
} else {
System.out.println("积分不足,不能抽奖");
activity.setState(activity.getNoRaffleState());
}
}
/**
* 是否抽中奖品
*/
@Override
public boolean raffle() {
System.out.println("正在抽奖,请稍等!");
int random = (int) (Math.random() * 10);
if (random == 0) {
activity.setState(activity.getDispenseState());
return true;
} else {
System.out.println("很遗憾,您没有中奖!");
activity.setState(activity.getNoRaffleState());
return false;
}
}
/**
* 发放奖品
*/
@Override
public void dispensePrize() {
System.out.println("没有奖品发放!");
}
}
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
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
/**
* 切换状态
*/
public class RaffleActivity {
@Setter
private State state;
private int count; //奖品数量
@Getter
@Setter
private int points;// 积分
@Getter
private State noRaffleState = new NoRaffleState(this);
@Getter
private State canRaffleState = new CanRaffleState(this);
@Getter
private State dispenseState = new DispenseState(this);
@Getter
private State dispenseOutState = new DispenseOutState(this);
public RaffleActivity(int count, int points) {
this.state = getNoRaffleState();
this.count = count;
this.points = points;
}
//扣除积分
public void deductPoints() {
if (points >= 50) {
state.deductPoints(points);
} else {
System.out.println("积分不足,不能抽奖");
state = getNoRaffleState();
}
}
public void raffle() {
// 如果当前的状态是抽奖成功
if (state.raffle()) {
//领取奖品
state.dispensePrize();
}
}
// 领取奖品
public int getCount() {
int curCount = count;
count--;
return curCount;
}
}
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
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
# 说明
- 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中。
- 方便维护。将容易产生问题的 if-else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if-else 语句,而且容易出错。
- 符合 “开闭原则”。容易增删状态。
但是会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度。
应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式。
上次更新: 2025/04/12, 05:37:39