一. 前言
1. 概述
实现命令模式的方式有很多, 本章使用Apache Commons Chain 实现命令模式。
2. 命令模式简介
命令模式是一种行为型的设计模式。它聚焦于请求数据, 把对请求数据的操作封装成一组命令对象。 由客户端直接发起对调用者的链路调用, 调用者完成对具体命令对象的编排(组织命令对象的执行顺序) 及其执行.
3. 命令模式适用场景
- 自动化流程处理: 客户端发起请求,即可由调用者组织命令对象完成一系列的步骤
- 多线程流式处理: 可以处理多个的任务的并发执行 (多个命令对象的并发执行任务)
对于一般固定流程的执行, 可以不用命令模式.
命令模式的优势体现在经常需要变更流程的场景:
a. 需要在多个命令的执行过程中, 新增命令对象 b. 需要重新编排命令对象的执行顺序
二. 使用步骤
1. 引入依赖
<dependency>
<groupId>commons-chain</groupId>
<artifactId>commons-chain</artifactId>
<version>1.2</version>
</dependency>
2. 定义命令对象
命令对象通过实现Command接口及其对应的execute方法完成逻辑处理。 execute方法返回Boolean类型, 可通过Command接口的静态变量返回。 CONTINUE_PROCESSING 表示继续执行下一个命令对象。 PROCESSING_COMPLETE 表示终止流程执行。
a. 校验登陆的命令对象
public class ValidateLoginCommand implements Command {
@Override
public boolean execute(Context context) throws Exception {
String loginName = (String) context.get("loginName");
System.out.println("执行了校验登陆的执行方法");
if (StringUtils.isNotEmpty(loginName)) {
return Command.CONTINUE_PROCESSING;
}
return Command.PROCESSING_COMPLETE;
}
}
b. 执行登陆的命令对象
public class ExecuteLoginCommand implements Command {
@Override
public boolean execute(Context context) throws Exception {
String password = (String) context.get("password");
System.out.println("执行了登陆命令的执行方法");
if (StringUtils.isEmpty(password)) {
return Command.PROCESSING_COMPLETE;
}
return Command.CONTINUE_PROCESSING;
}
}
3. 定义调用链对象
调用链对象通过继承ChainBase对象, 通过ChainBase对象的addCommand方法完成命令的添加
public class LoginChain extends ChainBase {
public LoginChain(){
super();
//添加命令对象的过滤器
addCommand(new LoginCommandFilter());
addCommand(new ValidateLoginCommand());
addCommand(new ExecuteLoginCommand());
}
}
4. 执行调用链的execute方法
execute方法的参数contexth实际就是各个命令对象使用的数据上下文。 类似LiteFlow框架的DefaultContext (工作台设计思想)
@RestController
@RequestMapping("/loginChain")
public class LoginChainController {
@GetMapping("/test")
public void test() throws Exception {
LoginChain loginChain = new LoginChain();
Context context = new ContextBase();
context.put("password","123");
loginChain.execute(context);
}
}
5. 扩展-命令对象的增强
有时候, 我们可能需要在命令对象执行前完成一些初始化步骤, 比如日志打印或者数据初始化, 在整个流程结束后完成资源的释放等动作。可以使用命令对象拦截器完成这个处理。 execute方法可以在命令对象的execute方法执行前先执行, 在所有命令对象执行完成后, 再执行对应的postprocess方法。该拦截器也需要添加到对应的调用链中 (见3中的代码注释: 添加命令对象的过滤器)
public class LoginCommandFilter implements Filter {
@Override
public boolean postprocess(Context context, Exception exception) {
System.out.println("执行了登陆命令过滤器的后置方法");
return false;
}
@Override
public boolean execute(Context context) throws Exception {
System.out.println("执行了登陆命令过滤器的执行方法");
return false;
}
}