1. 状态模式概述
概述
- 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
- 状态模式就是一个关于多态的设计模式,《代码整洁之道》和《重构》都提到:应使用多态取代条件表达式
特点
- 优点:将与特定状态相关的行为封装到一个状态对象中,使用多态代替 if-else 或者 switch-case 状态判断
- 缺点:必然导致类增加,这也是使用多态不可避免的问题
Demo
定义一个用户状态枚举类
1
2
3public enum State {
NORMAL, PLUS
}用户的功能接口
1
2
3public interface IUser {
void mockInterview();
}用户状态切换接口
1
2
3
4
5public interface ISwitchState {
void purchasePlus();
void expire();
}力扣用户类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class User implements IUser, ISwitchState {
private State state = State.NORMAL;
@Override
public void mockInterview() {
if (state == State.PLUS) {
System.out.println("开始模拟面试");
} else {
System.out.println("模拟面试是 Plus 会员专享功能");
}
}
@Override
public void purchasePlus() {
state = State.PLUS;
}
@Override
public void expire() {
state = State.NORMAL;
}
}- 判断用户状态会产生大量的分支判断语句,导致代码冗长
- 当状态有增加或减少时,需要改动多个地方,违反开闭原则
利用多态特性重构,为每个状态新建一个状态类。普通用户
1
2
3
4
5
6
7class Normal implements IUser {
public void mockInterview() {
System.out.println("模拟面试是 Plus 会员专享功能");
}
}PLUS 会员
1
2
3
4
5
6
7class Plus implements IUser {
public void mockInterview() {
System.out.println("开始模拟面试");
}
}使用状态模式的用户类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class User implements IUser, ISwitchState {
IUser state = new Normal();
public void mockInterview() {
state.mockInterview(); // 丑陋的状态判断语句消失了
}
public void purchasePlus() {
state = new Plus();
}
public void expire() {
state = new Normal();
}
}客户端测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Client {
public void test() {
// 用户初始状态为普通用户
User user = new User();
// 输出:模拟面试是 Plus 会员专享功能
user.mockInterview();
// 用户购买 Plus 会员,状态改变
user.purchasePlus();
// 输出:开始模拟面试
user.mockInterview();
// Plus 会员过期,变成普通用户,状态改变
user.expire();
// 输出:模拟面试是 Plus 会员专享功能
user.mockInterview();
}
}