目录
5.3 Spring Batch - Job Executor
引言
命令模式是一种行为设计模式,它允许你将请求封装为对象,从而使用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作。这种模式提供了一种解耦发送者和接收者的方式,使得系统更加灵活和易于扩展。
1. 命令模式简介
1.1 定义
命令模式将一个请求封装为一个对象,从而使你可用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作。这种模式允许你将发出请求的责任和执行请求的责任分割开。
1.2 解决的问题
- 当需要在不同的时刻指定请求,并将请求放入队列中,然后在稍后的时间执行这些请求时。
- 当需要实现撤销功能时。
- 当需要将请求发送者与请求接收者解耦时。
2. 设计模式的结构
2.1 类图
命令模式的主要参与者包括:
- Command (命令): 定义了一个执行操作的接口。
- ConcreteCommand (具体命令): 实现Command接口,持有接收者对象,并通过调用接收者的业务方法来执行命令。
- Receiver (接收者): 定义了执行操作的接口。
- Invoker (调用者): 请求一个命令对象执行这个命令。
类图如下所示:
+-------------------+ +-------------------+
| Command | | ConcreteCommand |
|--------------------| |--------------------|
| - execute() | | - receiver: Receiver|
|--------------------| |--------------------|
| + execute() | | + execute() |
+-------------------+ +-------------------+
+-------------------+ +-------------------+
| Receiver | | Invoker |
|--------------------| |--------------------|
| - action() | | - command: Command |
|--------------------| |--------------------|
| + action() | | + setCommand(cmd) |
| | | + executeCommand() |
+-------------------+ +-------------------+
2.2 示例代码
接下来,我们通过一个简单的例子来演示命令模式的应用:一个遥控器可以控制不同的电器设备。
// 接收者
interface Receiver {
void on();
void off();
}
class Light implements Receiver {
@Override
public void on() {
System.out.println("Light is on");
}
@Override
public void off() {
System.out.println("Light is off");
}
}
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令
class LightOnCommand implements Command {
private final Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
// 调用者
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public void undoButton() {
command.undo();
}
}
public class CommandPatternDemo {
public static void main(String[] args) {
Receiver light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(lightOn);
remoteControl.pressButton(); // Light is on
remoteControl.undoButton(); // Light is off
}
}
3. 优点
- 易于扩展: 可以轻松添加新的命令,而不需要修改现有的代码。
- 更好的封装: 封装了请求和请求的执行,使代码更清晰。
- 支持撤销: 可以方便地实现撤销操作。
- 职责分离: 发送者和接收者之间解耦,提高系统的灵活性。
4. 缺点
- 可能增加系统复杂性: 对于简单的应用场景来说,引入命令模式可能会增加不必要的复杂度。
- 可能增加内存消耗: 如果有大量命令实例存在,可能会占用较多的内存资源。
5. 实际应用
5.1 Spring AOP
Spring AOP(Aspect-Oriented Programming)允许开发者定义切面(aspect),并通过通知(advice)来封装特定的行为。通知可以看作是一个命令,它被定义为一个接口,并由具体的类来实现。例如,我们可以定义一个前置通知(Before advice)来表示在某个方法执行前需要执行的操作。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before method execution: " + joinPoint.getSignature());
// 执行目标方法
Object result = joinPoint.proceed();
System.out.println("After method execution: " + joinPoint.getSignature());
return result;
}
}
在这个例子中:
LoggingAspect
类扮演了命令的角色,它定义了在方法调用前后需要执行的操作。logAround
方法实现了ProceedingJoinPoint
接口的proceed
方法,这相当于命令模式中的execute
方法。@Around
注解指定了这是一个环绕通知,即在目标方法调用之前和之后都会执行的命令。
5.2 Spring MVC Controller
Spring MVC 中的控制器(Controller)可以被视为命令模式的一个应用。每个控制器方法都可以看作是一个命令,它接收HTTP请求并执行相应的业务逻辑。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExampleController {
@GetMapping("/greet")
public String greet() {
System.out.println("Executing Greeting Command");
return "Hello!";
}
}
在这个例子中:
ExampleController
类中的greet()
方法充当了命令的角色,它执行特定的业务逻辑。- HTTP请求触发了命令的执行。
5.3 Spring Batch - Job Executor
Spring Batch 是一个基于Spring的应用程序框架,用于处理大量的批处理任务。在这个框架中,一个作业(job)可以被视为一系列命令的组合,每个步骤(step)都是一个具体的命令。
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BatchJobExecutor {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job importUserJob;
public void executeImportUserJob() throws Exception {
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(importUserJob, jobParameters);
}
}
在这个例子中:
BatchJobExecutor
类包含了执行一个作业的方法。executeImportUserJob
方法扮演了调用者的角色,它负责触发作业的执行。JobLauncher
接口类似于命令模式中的调用者,它负责执行作业。importUserJob
对象代表了一个具体的命令,即执行用户导入作业。
6. 结论
命令模式是一种强大的设计模式,它有助于实现请求的封装、记录以及撤销等功能。通过将请求封装为对象,命令模式提高了系统的灵活性和可扩展性。Spring框架中的许多组件都隐含了命令模式的设计思想,这些应用展示了命令模式在实际项目中的灵活性和实用性。