Java设计模式——命令模式(Command Pattern)

目录

引言

1. 命令模式简介

1.1 定义

1.2 解决的问题

2. 设计模式的结构

2.1 类图

2.2 示例代码

3. 优点

4. 缺点

5. 实际应用

5.1 Spring AOP

5.2 Spring MVC Controller

5.3 Spring Batch - Job Executor

6. 结论


引言

命令模式是一种行为设计模式,它允许你将请求封装为对象,从而使用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作。这种模式提供了一种解耦发送者和接收者的方式,使得系统更加灵活和易于扩展。

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框架中的许多组件都隐含了命令模式的设计思想,这些应用展示了命令模式在实际项目中的灵活性和实用性。

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值