软件设计模式系列之十六——命令模式

news2024/12/23 9:59:56

目录

  • 1 模式的定义
  • 2 举例说明
  • 3 结构
  • 4 实现步骤
  • 5 代码实现
  • 6 典型应用场景
  • 7 优缺点
  • 8 类似模式
  • 9 小结

1 模式的定义

命令模式(Command Pattern)是一种行为型设计模式,旨在将请求发送者和接收者解耦,将一个请求封装为一个对象,从而允许您参数化客户端对象以进行不同的请求、排队请求或记录请求,并支持可撤销操作。

命令模式的核心思想是将一个请求包装成一个对象,包括请求的参数和接收者对象,然后客户端只需要调用该对象的方法来执行请求,而不需要关心请求的具体细节。这种方式使得请求的发送者和接收者之间的关系变得松耦合,同时支持一些附加功能,如命令的撤销和重做。

2 举例说明

为了更好地理解命令模式,让我们考虑一个实际的例子:遥控器控制家电。假设您有一个遥控器,可以控制不同种类的家电设备,如电视、音响和灯。每个按钮都代表一个命令,例如打开电视、关闭音响、调暗灯光等。命令模式可以用于实现这种遥控器系统。
在这里插入图片描述

在这个例子中,每个命令(如打开电视)都被封装成一个命令对象,包括具体的操作(执行命令)和接收者对象(执行命令的设备)。遥控器上的按钮只需要关联一个命令对象,并在按下按钮时执行该命令。这种方式使得遥控器可以轻松控制不同种类的家电设备,而不需要关心它们的具体实现。

3 结构

命令模式的结构包括以下几个关键部分:
在这里插入图片描述

Command(命令):定义一个执行操作的接口,通常包括一个 execute 方法,负责执行具体的命令。

ConcreteCommand(具体命令):实现命令接口,将一个接收者对象绑定到一个操作。它负责调用接收者的方法来执行命令。

Receiver(接收者):负责执行与请求相关的具体操作,是命令真正的执行者。

Invoker(调用者):负责将命令对象传递给接收者执行命令,它不需要知道命令的具体细节,只需调用命令的 execute 方法即可。

Client(客户端):创建具体命令对象,并将命令对象与接收者对象关联,然后将命令对象传递给调用者来执行。

4 实现步骤

实现命令模式时,通常遵循以下步骤:

定义命令接口(Command),其中包括一个 execute 方法用于执行命令。

创建具体命令类(ConcreteCommand),实现命令接口,并在构造函数中绑定一个接收者对象。

定义接收者类(Receiver),负责执行具体的操作。

创建调用者类(Invoker),负责接收命令对象并执行命令。

在客户端中创建命令对象和接收者对象,并将它们关联。然后将命令对象传递给调用者,由调用者执行命令。

5 代码实现

现在,让我们通过 Java 代码来实现上述遥控器控制家电的命令模式。

// 1. 定义命令接口
interface Command {
    void execute();
}

// 2. 创建具体命令类
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }
}

// 3. 定义接收者类
class Light {
    public void turnOn() {
        System.out.println("Light is on");
    }

    public void turnOff() {
        System.out.println("Light is off");
    }
}

// 4. 创建调用者类
class RemoteControl {
    private Command command;

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

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

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

        // 创建具体命令对象并关联接收者
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        // 创建调用者
        RemoteControl remote = new RemoteControl();

        // 设置命令并执行
        remote.setCommand(lightOn);
        remote.pressButton();

        remote.setCommand(lightOff);
        remote.pressButton();
    }
}

6 典型应用场景

命令模式在实际应用中有多种典型场景,包括但不限于:

遥控器控制:如上面的示例所示,可以用命令模式实现遥控器来控制不同的家电设备,如电视、音响和灯。

文本编辑器操作:文本编辑器中的撤销、重做、剪切、复制、粘贴等操作可以使用命令模式来实现。

菜单系统:图形用户界面(GUI)应用中的菜单项和按钮操作可以通过命令模式来处理。
在这里插入图片描述

游戏中的动作:在游戏中,角色的动作和命令(如攻击、防御、跳跃等)可以使用命令模式来处理。

多级撤销操作:命令模式支持撤销和重做操作,因此在需要多级撤销的应用中很有用,如图像编辑器或CAD软件。

日程安排应用:在日程安排应用中,可以使用命令模式来处理添加、编辑、删除事件等操作。

7 优缺点

优点:

解耦发送者和接收者:命令模式将请求的发送者和接收者解耦,发送者不需要知道接收者的具体实现,从而降低了系统的耦合度。

支持撤销和重做:命令模式可以轻松支持命令的撤销和重做,因为每个命令对象都包含了执行和撤销操作的逻辑。

支持扩展:可以轻松添加新的命令和接收者,而无需修改现有的客户端代码。

支持排队请求:命令模式允许将请求排队,以便按照先后顺序执行,或者实现任务调度。

缺点:

可能导致命令类膨胀:如果有大量的命令操作,可能会导致命令类的膨胀,增加维护的复杂性。

不适用于所有情况:命令模式不适用于所有场景,特别是对于简单的命令,直接调用方法可能更加简单和高效。

增加代码复杂性:引入命令模式会增加一定的代码复杂性,因为需要创建额外的命令类和接收者类。

8 类似模式

策略模式(Strategy Pattern):策略模式也可以用于封装可互换的行为,但它的主要目的是在运行时选择算法或策略,而不是将请求封装成命令对象。

观察者模式(Observer Pattern):观察者模式用于定义对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会收到通知。与命令模式不同,观察者模式不涉及命令的封装和执行。

中介者模式(Mediator Pattern):中介者模式用于减少对象之间的直接耦合,将对象之间的通信集中在一个中介者对象中。与命令模式不同,中介者模式通常用于管理对象之间的交互,而不是将请求封装成命令。

9 小结

命令模式是一种有用的设计模式,它允许将请求封装成命令对象,从而解耦请求的发送者和接收者,支持撤销和重做操作,并提供扩展性和灵活性。命令模式在实际应用中有多种典型场景,包括遥控器控制、文本编辑器操作、菜单系统等。虽然命令模式增加了一些复杂性,但它可以提高代码的可维护性和可扩展性,是面向对象设计中的重要模式之一。

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

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

相关文章

OmniOutliner 5 Pro for Mac(信息大纲记录工具)v5.12正式版 支持M1、M2

OmniOutliner 5 Pro是一款功能强大的大纲工具,可以帮助用户进行头脑风暴、组织思维和创建结构化的笔记。以下是这款软件的一些主要功能和特点: 大纲模式。OmniOutliner 5 Pro支持全屏模式、分屏模式、实时预览模式和导航模式等多种创作模式,…

RT-Thread 自动初始化机制

RT-Thread自动初始化机制 自动初始化机制是指初始化函数不需要被显示调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 例如在串口驱动中调用一个宏定义告知系统初始化需要调用的函数,代码如下: …

25814-2010 三聚氯氰 阅读笔记

声明 本文是学习GB-T 25814-2010 三聚氯氰. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了三聚氯氰的要求、采样、试验方法、检验规则以及标志、标签、包装、运输、贮存、安全、 安全技术说明书。 本标准适用于三聚氯氰的产品…

基于springboot+vue的大学生创新创业系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

idea 如何在命令行快速打开项目

背景 在命令行中从git仓库检出项目,如何在该命令行下快速用idea 打开当前项目,类似vscode 可以通过在项目根目录下执行 code . 快速打开当前项目。 步骤 以macos 为例 vim /usr/local/bin/idea 输入如下内容 #!/bin/sh open -na "IntelliJ IDE…

浅谈智能型电动机控制器在斯里兰卡电厂中的应用

摘要:传统的低压电动机保护是通过继电保护二次回路实现,但是我们结合电厂辅助控制设备的特点及其控制要求,推荐ARD2F智能型电动机控制器。以下综合介绍ARD2F智能型电动机控制器产品的特点及其智能化保护、测量、控制和通讯等。 Abstract: Th…

基于微信小程序的校园失物招领系统设计与实现(源码+lw+部署文档+讲解等)

前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…

PS7软件功能——相位、延迟测量

PicoScope 7 (PS7)软件增添了新的测量功能——测量相位之间的角度和延迟时间(图1)。 注:Phase- 相位;Delay - 延迟。 图1 相位测量 点击“Phase”,选择需要测量的通道,如下图选择的是…

idea 2021.2.3版本中隐藏target和.iml文件问题的解决

一 idea2021.2.3 版本隐藏文件 1.1 问题描述 添加隐藏文件内容后:没有可确定的保存按钮。无法实现添加隐藏文件。 1.2 解决办法 IDEA新建项目会自动生成一个.idea文件夹和.iml文件,开发中不需要对这两个文件修改,所以对以上文件进行隐藏处理…

重要采样的原理与实现

1. 引言 在雷达系统性能仿真时,由于雷达系统对虚警概率的要求,实现一定精度的仿真,所需要的Monte-Carlo实验次数将非常地高。重要采样可以在保障精度的前提下,大大降低Monte-Carlo实验次数。 网上有很多关于重要采样的原理介绍&…

94 # express 兼容老的路由写法

上一节实现了错误处理中间件,这一节来实现兼容老的路由写法 看个 express 的二级路由的例子 const express require("express"); const userRouter require("./routes/userRouter"); const articleRouter require("./routes/articleR…

AIGC: 区块链与数据安全

随着国家将区块链纳入战略发展规划,数字经济蓬勃发展。近年来,数据的流通成为了实体经济赋能的关键,而在这一过程中,区块链技术和数据安全变得至关重要。 中国已经成为全球最大的数据体,每天产生大量数据。数字经济已…

Unity 协程(Coroutine)的原理以及用法

目录 事件函数的执行顺序定义使用yield instruction中的子类 总结 参考链接 :Unity 5分钟基础的了解协程 事件函数的执行顺序 定义 定义:开启一段和主程序异步执行的逻辑异步执行:是指语句在异步执行模式下,各语句执行结束的顺序…

Python异步编程之web框架 异步vs同步 文件IO任务压测对比

主题:比较异步框架和同步框架在文件IO操作的性能差异python版本:python 3.8压测工具:locustweb框架:同步:flask 异步:aiohttp、starlette异步文件模块:aiofiles、anyio.Path请求并发量: 模拟10个…

EPICS sequencer状态机示例

状态机源代码: #define PVSYS "pvsysca" #define LIGHT "{prefix}:light" #define LIGHTON "{prefix}:lightOn" #define LIGHTOFF "{prefix}:lightOff" #define VOLTAGE "{prefix}:voltage" #define LO…

机器人过程自动化(RPA)入门 3. 顺序、流程图和控制流程

到目前为止,我们已经了解了RPA是什么,并且我们已经看到了通过记录任务的活动并运行它来训练UiPath机器人是多么简单。使用记录器的UiPath可以很容易地自动化日常任务。在我们开始自动化复杂的任务之前,让我们学习如何控制从一个到另一个的活动…

【算法分析与设计】算法概述

目录 一、学习要点二、算法的定义三、算法的性质四、程序(Program)五、问题求解(Problem Solving)六、算法的描述七、算法分析的目的八、算法复杂性分析(一)算法时间复杂性分析(二)算法渐近复杂性1、渐进上界记号-大O符号2、渐进下…

Prometheus+Grafana监控K8S集群(基于K8S环境部署)

文章目录 一、环境信息二、部署前准备工作三、部署Prometheus监控系统四、部署Node_exporter组件五、部署Kube_state_metrics组件六、部署Grafana可视化平台七、Grafana可视化显示Prometheus收集数据八、Grafana添加监控模板九、拓展 一、环境信息 1、服务器及K8S版本信息&…

现代卷积网络实战系列4:PyTorch从零构建VGGNet训练MNIST数据集

🌈🌈🌈现代卷积网络实战系列 总目录 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 1、MNIST数据集处理、加载、网络初始化、测试函数 2、训练函数、PyTorch构建LeNet网络 3、PyTorch从零构建AlexNet训练MNIST数据…

【7.Vue 利用Heatmap.js 制作自定义热力图】

1.效果 2.背景 需要根据后端检测的设备的数值显示设备周围的清洁度,用户希望用热力图的方式来显示,于是在网上找了资料,发现可以用Heatmap.js来实现。 Heatmap.js 官网:https://www.patrick-wied.at/static/heatmapjs/ 3.引入组件 安装Heatmap.js npm install Heatmap.…