命令模式的理解和实践

news2025/2/27 17:28:21

        在软件开发中,设计模式是开发者们经过长期实践总结出来的、可复用的解决方案,用于解决常见的设计问题。命令模式(Command Pattern)是行为型设计模式之一,它通过将一个请求封装成一个对象,从而允许用户用不同的请求对客户端进行参数化、对请求进行排队或者记录请求日志,以及支持可撤销的操作。本文将详细讲解命令模式的概念、原理、优点,并通过Java语言进行实践。

一、命令模式的概念

        命令模式的核心思想是将一个请求封装成一个对象,从而允许你使用不同的请求、队列请求、记录请求日志,以及支持可撤销的操作。命令模式将发出请求的对象(调用者)和执行请求的对象(接收者)解耦,使得请求可以通过不同的请求对象进行参数化、排队或记录。

        命令模式主要包含以下几个角色:

  1. 命令接口(Command):声明一个执行操作的接口。
  2. 具体命令类(ConcreteCommand):实现命令接口,将接收者对象绑定到具体的操作上,并调用接收者的方法来执行操作。
  3. 接收者类(Receiver):知道如何执行具体的操作,任何类都可以作为接收者。
  4. 调用者(Invoker):要求命令对象执行请求,它持有一个命令对象的引用。
  5. 客户端(Client):创建具体的命令对象,并设置命令对象的接收者。

二、命令模式的原理

        命令模式的原理在于将请求封装成对象,使得请求可以被存储、传递、序列化和执行。通过引入命令对象,调用者和接收者之间的依赖关系被解耦,调用者不再直接调用接收者的方法,而是通过命令对象来间接调用。

        具体来说,命令模式的原理包括以下几个步骤:

  1. 创建命令接口:定义一个通用的命令接口,声明一个执行操作的 execute() 方法。
  2. 实现具体命令类:针对每个具体的操作,创建一个实现命令接口的具体命令类。具体命令类持有一个接收者对象的引用,并在 execute() 方法中调用接收者的方法来执行操作。
  3. 创建接收者类:接收者类知道如何执行具体的操作,它包含了执行操作的方法。
  4. 创建调用者:调用者持有一个命令对象的引用,它可以在适当的时候调用命令对象的 execute() 方法来执行操作。调用者不需要知道具体的命令对象和接收者对象,它只需要知道命令接口。
  5. 客户端创建命令对象:客户端在需要执行某个操作时,创建具体的命令对象,并将接收者对象传递给命令对象。然后,客户端将命令对象传递给调用者,调用者会在适当的时候执行命令。

三、命令模式的优点

        命令模式具有以下几个优点:

  1. 解耦请求与实现:命令模式将请求与实现解耦,使得请求可以通过不同的命令对象进行参数化、排队或记录。
  2. 灵活性:由于命令对象可以被存储、传递和序列化,因此命令模式提供了更大的灵活性。例如,可以将命令对象存储在一个队列中,然后依次执行队列中的命令。
  3. 扩展性:命令模式易于扩展新的命令,只需添加新的具体命令类即可,无需修改现有的代码。
  4. 支持撤销操作:通过实现一个撤销操作的接口,命令模式可以支持撤销操作。

四、命令模式的实践

        下面,我们将通过Java语言来实现一个简单的命令模式示例。假设我们有一个简单的图形用户界面(GUI)应用程序,其中有几个按钮,每个按钮对应不同的操作,比如打开文件、保存文件和退出程序。我们可以使用命令模式来将这些操作封装成命令对象,从而简化按钮和操作的关联。

1. 创建命令接口

        首先,我们定义一个通用的命令接口 Command,它包含一个 execute() 方法。

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


2. 创建具体命令类

        接下来,我们针对每个具体的操作创建实现命令接口的具体命令类。例如,我们创建 OpenFileCommandSaveFileCommand 和 ExitCommand 三个具体命令类。

// 打开文件命令
public class OpenFileCommand implements Command {
    private Receiver receiver;

    public OpenFileCommand(Receiver receiver) {
        this.receiver = receiver;
    }

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

// 保存文件命令
public class SaveFileCommand implements Command {
    private Receiver receiver;

    public SaveFileCommand(Receiver receiver) {
        this.receiver = receiver;
    }

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

// 退出命令
public class ExitCommand implements Command {
    private Receiver receiver;

    public ExitCommand(Receiver receiver) {
        this.receiver = receiver;
    }

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


3. 创建接收者类

        然后,我们创建一个接收者类 Receiver,它包含执行具体操作的方法。

// 接收者类
public class Receiver {
    public void openFile() {
        System.out.println("File opened.");
    }

    public void saveFile() {
        System.out.println("File saved.");
    }

    public void exit() {
        System.out.println("Application exited.");
    }
}


4. 创建调用者

        接下来,我们创建一个调用者类 Invoker,它持有一个命令对象的引用,并可以在适当的时候调用命令对象的 execute() 方法。

// 调用者
public class Invoker {
    private Command command;

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

    public void executeCommand() {
        if (command != null) {
            command.execute();
        }
    }
}


5. 客户端创建命令对象

        最后,我们在客户端代码中创建具体的命令对象,并将接收者对象传递给命令对象。然后,将命令对象传递给调用者,并在适当的时候执行命令。

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建接收者对象
        Receiver receiver = new Receiver();

        // 创建命令对象
        Command openFileCommand = new OpenFileCommand(receiver);
        Command saveFileCommand = new SaveFileCommand(receiver);
        Command exitCommand = new ExitCommand(receiver);

        // 创建调用者对象
        Invoker invoker = new Invoker();

        // 设置命令并执行
        invoker.setCommand(openFileCommand);
        invoker.executeCommand();

        invoker.setCommand(saveFileCommand);
        invoker.executeCommand();

        invoker.setCommand(exitCommand);
        invoker.executeCommand();
    }
}


        运行客户端代码,输出如下:

File opened.
File saved.
Application exited.


总结

        命令模式是一种强大的行为型设计模式,它通过将一个请求封装成一个对象,使得请求可以被存储、传递、序列化和执行。命令模式将发出请求的对象(调用者)和执行请求的对象(接收者)解耦,使得请求可以通过不同的命令对象进行参数化、排队或记录。命令模式具有解耦请求与实现、灵活性、扩展性和支持撤销操作等优点。通过本文的讲解和实践,相信读者对命令模式有了更深入的理解,并能够在实际开发中灵活运用该模式。

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

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

相关文章

vue-router查漏补缺

一、动态路由匹配 1.带参数的动态路由匹配 import User from ./User.vue// 这些都会传递给 createRouter const routes [// 动态字段以冒号开始{ path: /users/:efg, component: User }, ]这种方式的路由会匹配到/users/abc或者/users/123,路径参数用冒号:表示,并…

Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】

anaconda可以提供多个独立的虚拟环境,方便我们学习深度学习(比如复现论文); Pycharm编辑器可以高效的编写python代码,也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程: 1.Anaconda安装 下载Ana…

三维测量与建模笔记 - 6.2 结构光三维成像简介

简介 双目视觉系统中,找到左右图像中的同名点是很困难的。 即便是经过了极线校正,也存在很多问题比如高光等造成无匹配。对于结构光方案来说,找到同名点的过程会相对简单些。 结构光方案中,会增加一个投射器,将编码后的…

this version of the Java Runtime only recognizes class file versions up to 52.0

问题描述 Exception in thread "main" java.lang.UnsupportedClassVersionError: com/xxx/Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versi…

【开源免费】基于SpringBoot+Vue.JS在线办公系统(JAVA毕业设计)

本文项目编号 T 001 ,文末自助获取源码 \color{red}{T001,文末自助获取源码} T001,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

【WRF理论第十三期】详细介绍 Registry 的作用、结构和内容

目录 1. Introduction:介绍 Registry 的作用和功能。2. Registry Contents:详细描述 Registry 的结构和内容,包括各个部分的条目类型。2.1. DIMSPEC ENTRIES(维度规格条目)2.2. STATE ENTRIES(状态变量条目…

Redis篇-4--原理篇3--Redis发布/订阅(Pub/Sub)

1、概述 Redis 发布/订阅(Publish/Subscribe,简称 Pub/Sub)是一种消息传递模式,允许客户端订阅一个或多个通道(channel),并接收其他客户端发布到这些通道的消息。 2、Redis 发布/订阅的主要概…

[大数据]Hudi编译集成

1. Hudi概述 1.1 Hudi简介 What is Apache Hudi Apache Hudi is the next generation streaming data lake platform. Apache Hudi brings core warehouse and database functionality directly to a data lake. Hudi provides tables, transactions, efficient upserts/dele…

Redis 数据结构(一)—字符串、哈希表、列表

Redis(版本7.0)的数据结构主要包括字符串(String)、哈希表(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)、超日志&#xff08…

Cisco Packet Tracer | Cisco Packet Tracer - VLAN 实验 - 交换机的 VLAN 划分

关注这个工具的其它相关笔记:Cisco Packet Tracer —— 使用教程合集-CSDN博客 0x01:VLAN 划分 - 单个交换机 0x0101:拓扑搭建流程 从软件底部拖出一台交换机(笔者选择的型号是 2960 IOS15): 然后再拖出四…

元宇宙时代的社交平台:Facebook的愿景与实践

随着科技的不断进步,元宇宙(Metaverse)这一概念逐渐走进了人们的视野。作为全球最大的社交平台之一,Facebook(现Meta)在这场元宇宙革命中扮演着重要角色。Meta不仅在不断扩展其社交平台的边界,还…

Nignx部署Java服务测试使用的Spring Boot项目Demo

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

计算机网络ENSP课设--三层架构企业网络

本课程设计搭建一个小型互联网,并模拟Internet的典型Web服务过程。通过此次课程设计,可以进一步理解Internet的工作原理和协议过程,并提高综合知识的运用能力和分析能力。具体目标包括: (1)掌握网络拓扑的…

记一次:使用C#创建一个串口工具

前言:公司的上位机打不开串口,发送的时候设备总是关机,因为和这个同事关系比较好,编写这款软件是用C#编写的,于是乎帮着解决了一下(是真解决了),然后整理了一下自己的笔记 一、开发…

SQL 获取今天的当月开始结束范围:

使用 GETDATE() 结合 DATEADD() 和 DATEDIFF() 函数来获取当前月的开始和结束时间范围。以下是实现当前月时间范围查询的 SQL&#xff1a; FDATE > DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) FDATE < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) 1, 0) …

利用Java爬虫MinC根据ID获取商品详情的完整指南

在当今数字化时代&#xff0c;获取商品详情数据对于市场分析、价格监控和竞争对手分析至关重要。Java作为一种强大且广泛使用的编程语言&#xff0c;非常适合开发复杂的爬虫系统。本文将详细介绍如何利用Java编写爬虫程序来根据商品ID获取商品详情&#xff0c;并提供完整的代码…

RabbitMQ-入门

RabbitMQ-入门 基本说明 AMQP协议&#xff08;高消息队列协议&#xff1a;Advanced Message Queuing Protocol&#xff09;&#xff1a;https://www.rabbitmq.com/tutorials/amqp-concepts.html 基础组件术语 生产者&#xff08;Publisher&#xff09;&#xff1a;发消息到某…

【JAVA项目】基于ssm的【美食推荐管理系统】

【JAVA项目】基于ssm的【美食推荐管理系统】 技术简介&#xff1a;采用JSP技术、B/S架构、SSM框架、MySQL技术等实现。 系统简介&#xff1a;美食推荐管理系统&#xff0c;在系统首页可以查看首页、热门美食、美食教程、美食店铺、美食社区、美食资讯、我的、跳转到后台等内容。…

go-zero(十二)消息队列

go zero 消息队列 在微服务架构中&#xff0c;消息队列主要通过异步通信实现服务间的解耦&#xff0c;使得各个服务可以独立发展和扩展。 go-zero中使用的队列组件go-queue&#xff0c;是gozero官方实现的基于Kafka和Beanstalkd 的消息队列框架,我们使用kafka作为演示。 一、…

day30-IO-阶段综合案例(带权重的随机每日一记)(笔记完全来源于黑马程序员)

目录 0 目录一、听黑马阿玮的视频记录的笔记1. 制造假数据1.1 如何制造假数据1.2 练习1-生成方式1&#xff1a;爬取姓氏、男生名字、女生名字1.3 练习2-生成方式1&#xff1a;在练习1的基础上&#xff0c;将数据写入本地文件1.4 练习3-生成方式2&#xff1a;利用糊涂包生成假数…