顽强的毅力可以征服世界上任何一座高峰。——狄更斯
我们在实现审核业务的时候,可能在没使用状态模式的时候,使用if else
或者switch case
进行操作
ruben
说:我不能针对不同的状态写多个后端接口吗?
achao
说:那你前端还是要使用if else
去根据不同的状态调用不同的接口啊
我这里模拟一个简单的审核,真实项目中的业务将比这复杂
我们在用户提交审核后,状态应该是待审核
在待审核时执行操作,如果用户提交的内容为空,则将状态更改为审核未通过
在待审核时执行操作,如果用户提交的内容不为空,则将状态更改为审核已通过
在审核未通过时,如果用户再次执行操作,提示重新提交审核
在审核已通过时,如果用户再次执行操作,提示审核已通过
这里我们采用状态模式实现:
首先定义一个状态接口:
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
| package com.ruben.state.example;
import java.util.Map;
public interface ApprovalStatus { String CONTENT = "content"; String STATUS = "status";
Map<String, Object> execute(Map<String, Object> param);
void setExecutor(ApprovalExecutor executor); }
|
其中包含我们主要的审核操作以及设置操作类的方法,以及两个常量
这里的操作类下面会提到
然后是抽象类,包含我们共有方法,例如给状态设置操作类,这里将操作类设为protected
,允许子类状态访问该操作类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.ruben.state.example;
public abstract class BaseStatus implements ApprovalStatus {
protected ApprovalExecutor executor;
@Override public void setExecutor(ApprovalExecutor executor) { this.executor = executor; } }
|
然后是实现各个状态:
待审核
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
| package com.ruben.state.example;
import java.util.Collections; import java.util.Map; import java.util.Objects;
public class WaitStatus extends BaseStatus {
@Override public Map<String, Object> execute(Map<String, Object> param) { boolean pass = Objects.nonNull(param.get(CONTENT)); ApprovalStatus status; if (pass) { status = new PassStatus(); } else { System.out.println("提交内容为空,审核未通过"); status = new RejectStatus(); } executor.changeStatus(status); return Collections.singletonMap(STATUS, status.getClass().getSimpleName()); } }
|
已通过:
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
| package com.ruben.state.example;
import java.util.Collections; import java.util.Map;
public class PassStatus extends BaseStatus {
@Override public Map<String, Object> execute(Map<String, Object> param) { System.out.println("您已经通过审核了,不能进行操作啦!"); return Collections.singletonMap(STATUS, this.getClass().getSimpleName()); } }
|
已拒绝:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.ruben.state.example;
import java.util.Collections; import java.util.Map;
public class RejectStatus extends BaseStatus {
@Override public Map<String, Object> execute(Map<String, Object> param) { System.out.println("您未通过审核,请重新提交审核!"); return Collections.singletonMap(STATUS, this.getClass().getSimpleName()); } }
|
然后就是我们的操作类了
这里将状态接口作为成员变量
提供一个带参构造器,让我们初始具有一个状态
提供一个变更状态的方法,应对状态变更的情况,顺便将我们的操作类传递给对应的状态
提供一个审核方法,该方法就是我们在客户端实际操作的方法,它会根据不同的状态(实际的状态实现类)调用对应的实现
操作类避免了直接操作对应的方法,减少了我们代码中的if else
/switch case
等
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
| package com.ruben.state.example;
import java.util.Map;
public class ApprovalExecutor {
private ApprovalStatus status;
public ApprovalExecutor(ApprovalStatus status) { this.status = status; }
public void changeStatus(ApprovalStatus status) { this.status = status; status.setExecutor(this); }
public Map<String, Object> execute(Map<String, Object> param) { return status.execute(param); }
}
|
最后是运行方法:
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
| package com.ruben.state.example;
import java.util.HashMap; import java.util.Map;
public class ApprovalApplication { public static void main(String[] args) { Map<String, Object> param = new HashMap<>(1 << 2); System.out.println("用户提交审核"); WaitStatus waitStatus = new WaitStatus(); ApprovalExecutor executor = new ApprovalExecutor(waitStatus); waitStatus.setExecutor(executor); Map<String, Object> result = executor.execute(param); System.out.println(result); System.out.println("再次尝试提交"); executor.execute(param); System.out.println("用户填写内容"); param.put(ApprovalStatus.CONTENT, "666"); System.out.println("用户再次提交审核"); executor.changeStatus(waitStatus); result = executor.execute(param); System.out.println(result); executor.execute(param);
} }
|
状态模式优点
- 单一职责原则。 将与特定状态相关的代码放在单独的类中。
- 开闭原则。 无需修改已有状态类和上下文就能引入新状态。
- 通过消除臃肿的状态机条件语句简化上下文代码。
状态模式缺点
- 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。