Java设计模式之命令模式介绍和案例示范

news2024/11/9 10:18:59
一、命令模式简介

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,从而使你可以用不同的请求对客户端进行参数化、对请求排队或记录日志,以及支持可撤销的操作。命令模式的核心思想是将发出请求的对象与执行请求的对象分离,从而解耦请求的调用与处理逻辑。

在实际开发中,命令模式常用于实现事务管理、任务队列、操作撤销/重做等功能。该模式的关键优势在于它能够灵活地将不同的操作封装为命令对象,并通过组合、记录、重放等手段,实现复杂的操作逻辑。

二、命令模式的结构

命令模式的典型结构包括:

  1. Command:命令接口,声明了执行操作的接口。
  2. ConcreteCommand:具体命令类,实现了Command接口,负责定义请求的具体行为。
  3. Invoker:调用者,负责调用命令对象执行请求,通常持有一个或多个命令对象。
  4. Receiver:接收者,负责真正执行命令的逻辑。
  5. Client:客户端,负责创建命令对象,并将其与具体的接收者关联。

类图如下:
在这里插入图片描述

三、命令模式的使用场景
  1. 参数化请求:当系统需要对不同请求进行参数化时,可以使用命令模式将不同请求封装为独立的命令对象。
  2. 队列请求处理:当需要将请求放入队列中排队执行时,命令模式能够将请求对象化,从而方便地进行队列操作。
  3. 可撤销操作:通过命令模式,可以实现操作的撤销与重做功能。
四、命令模式的优缺点

优点

  • 松耦合:命令模式将请求的发出者与执行者解耦,降低了系统的耦合度。
  • 扩展性强:可以很容易地添加新的命令类来扩展系统的功能,而无需修改现有代码。
  • 支持撤销/重做:通过记录命令对象,可以方便地实现操作的撤销与重做功能。

缺点

  • 命令类数量增多:对于每一个具体操作都需要创建一个命令类,可能会导致类的数量增多,增加系统复杂性。
五、命令模式在电商交易系统中的应用

在电商交易系统中,命令模式可以用于以下场景:

  1. 订单操作的撤销与重做:假设系统需要支持订单操作的撤销与重做功能,可以使用命令模式将每个操作封装为一个命令对象,并记录这些操作,从而实现操作的撤销与重做。
  2. 任务队列的管理:在处理大量订单或库存更新时,可以使用命令模式将每个任务封装为命令对象,放入任务队列中按顺序执行,保证系统的稳定性和处理效率。

示例代码

// 命令接口
interface OrderCommand {
    void execute();
}

// 接收者
class OrderReceiver {
    public void createOrder() {
        System.out.println("Creating order.");
    }
    public void cancelOrder() {
        System.out.println("Cancelling order.");
    }
}

// 具体命令类 - 创建订单
class CreateOrderCommand implements OrderCommand {
    private OrderReceiver receiver;

    public CreateOrderCommand(OrderReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.createOrder();
    }
}

// 具体命令类 - 取消订单
class CancelOrderCommand implements OrderCommand {
    private OrderReceiver receiver;

    public CancelOrderCommand(OrderReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.cancelOrder();
    }
}

// 调用者
class OrderInvoker {
    private OrderCommand command;

    public void setCommand(OrderCommand command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
    }
}

public class CommandPatternExample {
    public static void main(String[] args) {
        OrderReceiver receiver = new OrderReceiver();
        OrderCommand createOrder = new CreateOrderCommand(receiver);
        OrderCommand cancelOrder = new CancelOrderCommand(receiver);

        OrderInvoker invoker = new OrderInvoker();
        invoker.setCommand(createOrder);
        invoker.executeCommand();  // 输出: Creating order.

        invoker.setCommand(cancelOrder);
        invoker.executeCommand();  // 输出: Cancelling order.
    }
}

在这个示例中,CreateOrderCommandCancelOrderCommand 分别实现了创建订单和取消订单的功能。通过 OrderInvoker 类,客户端可以动态选择执行哪种命令,并且可以方便地实现操作的撤销与重做。

六、命令模式的常见问题和解决方式

问题1:命令类过多,导致系统复杂性增加

解决方式:可以通过命令工厂模式简化命令对象的创建过程,减少客户端直接操作命令对象的负担。此外,还可以将一些简单的命令类合并,减少类的数量。

问题2:撤销/重做功能实现复杂

解决方式:通过命令对象中保存操作的状态和参数,可以较容易地实现撤销和重做功能。此外,可以将命令对象与状态管理器结合,集中管理命令的撤销与重做操作。

问题3:命令对象的生命周期管理复杂

解决方式:通过引入命令队列或命令池来管理命令对象的生命周期,避免内存泄漏或对象重复创建带来的性能问题。

七、命令模式与策略模式的区别

命令模式与策略模式都是行为型设计模式,但它们有不同的应用场景和设计意图。

1. 命令模式 vs 策略模式

  • 目的
    • 命令模式旨在将请求封装为对象,从而使得不同的请求可以用相同的方式进行处理,并支持请求的撤销和重做。
    • 策略模式则用于定义一系列算法,将每个算法封装为一个策略类,并允许算法在运行时替换。
  • 应用场景
    • 命令模式适用于需要对请求进行排队、记录、撤销/重做的场景。
    • 策略模式适用于需要动态选择不同算法或行为的场景。
  • 结构
    • 命令模式通常包括命令类、接收者类、调用者类和客户端类。命令类负责封装请求,接收者类执行请求,调用者类触发命令的执行。
    • 策略模式通常包括策略接口、多个具体策略类和上下文类。上下文类负责管理策略对象,并在需要时调用策略对象执行具体的算法。

示例代码

// 策略接口
interface PaymentStrategy {
    void pay(int amount);
}

// 具体策略类 - 支付宝支付
class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("Paying " + amount + " using Alipay.");
    }
}

// 具体策略类 - 微信支付
class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("Paying " + amount + " using WeChat Pay.");
    }
}

// 上下文类
class PaymentContext {
    private PaymentStrategy strategy;

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void executePayment(int amount) {
        strategy.pay(amount);
    }
}

public class StrategyPatternExample {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();

        // 使用支付宝支付
        context.setStrategy(new AlipayStrategy());
        context.executePayment(100);  // 输出: Paying 100 using Alipay.

        // 使用微信支付
        context.setStrategy(new WeChatPayStrategy());
        context.executePayment(200);  // 输出: Paying 200 using WeChat Pay.
    }
}

在这个示例中,PaymentStrategy 定义了支付的策略接口,AlipayStrategyWeChatPayStrategy 分别实现了支付宝支付和微信支付的具体逻辑。通过策略模式,可以灵活地切换支付方式,而无需修改上下文类的代码。

八、命令模式在开源框架中的应用示范

1. Spring任务调度中的命令模式

在Spring框架中,任务调度器(Task Scheduler)是一个非常有用的工具,允许我们在特定的时间点或周期性地执行任务。通过将任务封装为一个命令对象,任务调度器可以在指定时间执行这些任务,这实际上就是命令模式的应用。

1.1 基本原理

在命令模式中,命令(Command)通常是一个实现了某种接口的对象,它封装了某个操作的所有信息。这个操作可以是某个具体的业务逻辑,比如发送一封邮件、生成一份报告等。在Spring的任务调度器中,这些命令通常实现了 Runnable 接口,并且可以由调度器在指定的时间执行。

1.2 代码示例

下面我们通过一个具体的代码示例来展示如何使用Spring的任务调度器实现命令模式。

1.2.1 准备工作

首先,我们需要在Spring应用中配置任务调度器。这里我们使用ConcurrentTaskScheduler,它是Spring提供的一个简单的任务调度器实现。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;

import java.util.Date;

@Configuration
public class CommandPatternExample {

    @Bean
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();  // 配置任务调度器
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CommandPatternExample.class);
        TaskScheduler scheduler = context.getBean(TaskScheduler.class);

        // 创建命令对象
        Runnable command = new PrintTimeCommand();
        
        // 在5秒后执行命令
        scheduler.schedule(command, new Date(System.currentTimeMillis() + 5000));

        context.close();
    }
}

1.2.2 创建命令对象

接下来,我们定义一个实现 Runnable 接口的命令对象。这个对象封装了具体的操作逻辑,即在控制台上打印当前时间。

public class PrintTimeCommand implements Runnable {

    @Override
    public void run() {
        System.out.println("Current time: " + new Date());
    }
}

1.2.3 运行示例

当你运行上述代码时,Spring任务调度器将在5秒后执行PrintTimeCommand命令,并输出当前的时间。输出示例如下:

Current time: Wed Aug 21 14:28:45 UTC 2024

通过这种方式,PrintTimeCommand 作为一个命令对象,被任务调度器在特定时间执行。这就是命令模式在Spring任务调度中的实际应用。

2. 命令模式的优势

通过上述示例可以看到,命令模式在Spring框架中有以下几个优势:

  • 解耦请求发送者和执行者:命令模式将任务的创建和执行解耦,使得我们可以独立地管理任务的执行时间和逻辑。
  • 灵活性高:我们可以根据需要创建不同的命令对象,并在调度器中灵活配置这些命令的执行时间。
  • 易于扩展:新的命令可以通过实现 Runnable 接口轻松添加,无需修改现有代码。
九、总结

命令模式通过将请求封装为对象,实现了请求的参数化、排队、记录和可撤销操作,在系统设计中具有广泛的应用场景。相比于策略模式,命令模式更适合处理请求的排队和管理,而策略模式则更注重算法的动态选择。两者在实际应用中各有侧重,开发者应根据具体需求选择合适的模式来实现系统的灵活性和扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照以及工作常用总结

文章目录 kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照一、kvm 虚拟机命令行虚拟机操作(创建和删除)查看虚拟机virt-install创建一个虚拟机关闭虚拟机重启虚拟机销毁虚拟机 二、kvm 制作快照和恢复快照**创建快照**工作常见问题创建快照报错::intern…

超详细、史上最全pytorch安装教程

一、anaconda安装 1.下载 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrorhttps://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 这里划到最下面选择5.3.1最新版: 2.下载完成后安装 点击next 点击 I agree 选择All Us…

ignav的INS的状态更新

ignav的代码 static void updstat(const insopt_t *opt,insstate_t *ins,const double dt,const double *x0,const double *P0,double *phi,double *P,double *x,double *Q) {opt->exprn?getprn(ins,opt,dt,Q): getQ(opt,dt,Q); // //phi 状态转移矩阵 ,离散化…

算法学习攻略总结 : 入门至进阶,通关之路指南

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; <搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到…

CircleProgressView 鸿蒙ArkTS自定义View实现圆形进度条

上篇的截图中除了一个上下的箭头&#xff0c;还有一个圆形进度条&#xff0c;今天我们来讲讲这个如何进行实现 我们看这个图形的构造&#xff0c;其实很简单&#xff1a;一个圆形图形&#xff0c;以及一个文本来显示进度 所以我们用一个层叠布局 绘制一个带颜色的圆形&#xff…

『功能项目』播放动画时禁止点击移动【40】

我们打开上一篇39GameObject对象池 - 第三职业的项目&#xff0c; 本章要做的事情是在第三职业播放续航攻击动画时禁止点击时触发的移动函数&#xff0c;换句话说是在播放攻击动画时禁止移动 修改脚本&#xff1a;PlayerRayClickNavigation.cs 运行项目 - 播放第三职业续航技能…

2-92 基于matlab的KPCA的TE过程的故障监测

基于matlab的KPCA的TE过程的故障监测&#xff0c;利用核主元分析法(KPCA)来进行故障检测的思想,将输入空间中复杂的非线性问题转化为特征空间中的线性问题&#xff0c;计算步骤&#xff1a;&#xff08;1&#xff09; 选择监控变量&#xff0c;收集正常工况下的各变量的样本&am…

【警告 C6031:返回值被忽略:scanf】

警告 C6031 返回值被忽略: “scanf”。 错误 C4996 scanf: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #include <stdio.h> int max(int x, int y…

OKHttp实现原理分享

前言介绍 大约在2年半之前&#xff0c;就想写一篇关于OKHttp原理的文章&#xff0c;一来深入了解一下其原理&#xff0c;二来希望能在了解原理之后进行更好的使用。但是因为种种原因&#xff0c;一直无限往后推迟&#xff0c;最近因为我们情景智能半个月一次的分享轮到我了&…

手势识别&手势控制系统-OpenCV&Python(源码和教程)

项目特点 手部手势识别&#xff1a; 项目利用计算机视觉技术来识别手部的各种手势。这种技术可以应用于多种场景&#xff0c;比如人机交互、游戏控制、无障碍技术等。 自定义手势&#xff1a; 用户可以自定义手势&#xff0c;这意味着可以通过训练新的手势模式来扩展系统的功能…

基于vue框架的城市网约车管理系统v34td(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,司机,订单评价,完成订单,司机接单,打车订单 开题报告内容 基于Vue框架的城市网约车管理系统开题报告 一、研究背景与意义 1.1 研究背景 随着城市化进程的加速和互联网技术的飞速发展&#xff0c;网约车服务作为一种新兴的出行方…

基于java+SpringBoot+Vue的阿博图书馆管理系统设计与实现

开发语言:Java 数据库:MySQL技术:SpringBootMyBatis工具:IDEA/Ecilpse、Navicat、Maven 系统简介 阿博图书馆管理系统是一款基于Java、SpringBoot和Vue.js技术开发的信息化管理系统&#xff0c;旨在为图书馆提供一个高效、便捷的图书管理与借阅服务。系统通过B/S架构&#x…

FinalShell连接Linux服务器并解决反复输入密码问题

FinalShell是一款由国人开发的SSH客户端工具&#xff0c;它支持多平台&#xff0c;包括Windows、Mac OS X和Linux。FinalShell主要用于一体化服务器管理&#xff0c;它不仅是一个SSH客户端&#xff0c;还具备强大的开发和运维功能&#xff0c;能够充分满足开发和运维的需求。 本…

人脸匿名化初步研究:解决人脸隐私安全

1、人脸匿名化定义&#xff1a; 将人脸图像匿名化方法从图像语义修改、图像语义保持、视觉可恢复以及深度学习过程中的人脸隐私保护四个方面进行分类&#xff0c;将人脸视频匿名化方法从聚焦面部区域隐私的视频匿名化方法和面向生物特征隐私的视频匿名化方法两个方面进行分类 …

开源FormCreate低代码表单组件的配置项和事件的详解

在使用开源FormCreate低代码表单时&#xff0c;您可以通过各种 props 来定制表单的行为和外观。这些参数允许您控制表单的生成规则、配置选项、双向数据绑定等&#xff0c;为复杂的表单场景提供了强大的支持。 源码地址: Github | Gitee FormCreate组件Props 以下是常用的 pr…

【项目开发 | Python】基于“羊了个羊“风格的消除类小游戏

原创文章,不得转载。 目标:使用 Python 开发"羊了个羊"风格的消除类小游戏,合理运用 AIGC 工具提高开发效率;使用文生图工具实现图片设计等工作。 文章目录 项目背景项目介绍+项目展示游戏逻辑概述主界面游戏界面获胜界面失败界面附加功能项目细节项目测试测试样…

zabbix之钉钉告警

钉钉告警设置 我们可以将同一个运維组的人员加入到同一个钉钉工作群中&#xff0c;当有异常出现后&#xff0c;Zabbix 将告警信息发送到钉钉的群里面&#xff0c;此时&#xff0c;群内所有的运维人员都能在第一时间看到这则告警详细。 Zabbix 监控系统默认没有开箱即用…

JavaScript进阶day4

目录 1.深浅拷贝 1.1 浅拷贝 1.1.1 浅拷贝的认识 1.1.2 浅拷贝的小结 1.2 深拷贝 1.2.1 递归实现深拷贝 1.2.2 js类库lodash/cloneDeep实现深拷贝 1.2.3 JSON.stringify()实现深拷贝 2.异常处理 2.1 throw 抛异常 2.2 try /catch 捕获异常 2.3 debugger 3.处理thi…

嵌入式边缘计算:融合创新与未来展望

本文深入探讨了嵌入式边缘计算。首先解析了其概念&#xff0c;指出它是将计算和数据存储能力嵌入边缘设备以实现本地数据处理。阐述了其低延迟、高可靠性、节省带宽、隐私保护和高效节能等技术特点。接着介绍了关键技术&#xff0c;包括嵌入式系统设计、边缘计算架构、通信技术…

关于QT服务端客户端的聊天

服务段头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> #include<QMessageBox> #include<QDebug> #include<QList> #include<QTcpSocket>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_N…