首页 > 其他分享 >设计模式详解(命令模式)

设计模式详解(命令模式)

时间:2024-10-11 16:17:57浏览次数:9  
标签:调用者 void 模式 命令 详解 Command editor 设计模式 public

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,从而使得请求的发送者和接收者解耦。

一、命令模式的核心思想
命令模式的核心思想是将“请求”封装成为一个对象,从而使得我们可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

二、命令模式的结构
在命令模式结构图中,通常包含以下几个角色:

  1. Command(抽象命令类):一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
  2. ConcreteCommand(具体命令类):抽象命令类的子类,实现了在抽象命令类中声明的方法。它对应具体的接收者对象,将接收者对象的动作绑定其中。
  3. Invoker(调用者):请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。
  4. Receiver(接收者):执行与请求相关的操作,它具体实现对请求的业务处理。
  5. Client(客户端):创建具体的命令对象,并且设置命令对象的接收者。这里的客户端并不是常规意义上的客户端,而是在组装命令对象和接收者,也可以将其称为装配者。

三、命令模式的实现

命令模式的实现通常涉及以下几个步骤:

  1. 定义一个抽象的Command接口,其中声明一个execute()方法。
  2. 具体的命令类(ConcreteCommand)实现这个execute()方法,将一个发送者(Invoker)的请求转换为一个或多个接收者(Receiver)的操作。
  3. 发送者(Invoker)并不知道接收者的具体实现,它只需要触发命令对象的execute()方法即可。

四、命令模式的应用场景

命令模式有广泛的应用场景,主要包括以下几种:

  1. 将各种请求以命令的形式加入到队列中,然后由相应的线程或进程逐个执行这些命令。
  2. 将一系列相关的操作封装成一个命令,要么全部执行成功,要么全部回滚。
  3. 通过保存历史命令,可以轻松地实现撤销和重做功能。
  4. 在执行命令的时候,可以同时将该命令记录到日志中,用于审计跟踪。
  5. 命令对象可以实现一个undo()方法,用于撤销之前执行的命令。
  6. 将多个命令组合成一个复合命令,可以一次性执行一系列操作。
  7. 在GUI程序中,可以使用命令模式来发出和处理用户点击按钮时表示的操作。
  8. 在多线程操作中,命令模式可以帮助程序在后台自动发出指令并处理其他业务,而不用等待线程完成操作。

五、命令模式的优点

  1. 降低了系统的耦合度:由于请求者与接收者之间通过命令对象进行交互,因此它们之间的依赖关系被解耦。
  2. 增强了系统的扩展性:新的命令可以很容易地添加到系统中,而不需要修改现有的客户端代码。
  3. 提供了命令的撤销和重做功能:通过保存历史命令,可以轻松地实现撤销和重做功能。
  4. 实现了请求的排队和日志记录:命令对象可以被存储在队列中,并在适当的时候执行。同时,也可以在执行命令的时候记录日志。

六、命令模式的缺点

  1. 增加了系统的复杂性:由于引入了抽象命令类、具体命令类、调用者和接收者等多个角色,系统的复杂性可能会增加。
  2. 可能会导致过度设计:如果系统中的命令数量并不多,或者命令的执行逻辑比较简单,那么使用命令模式可能会导致过度设计。

七、实战流程
不使用命令模式

public class Editor {
    public void copy() {
        // 复制逻辑
    }

    public void paste() {
        // 粘贴逻辑
    }

    public void undo() {
        // 撤销逻辑
    }
}

public class User {
    public static void main(String[] args) {
        Editor editor = new Editor();
        editor.copy();
        editor.paste();
        editor.undo();
    }
}

使用命令模式优化

/**
 * 接收者
 */
public class Editor {
    public void copy() {
        System.out.println("复制内容");
    }

    public void paste() {
        System.out.println("粘贴内容");
    }

    public void undo() {
        System.out.println("撤销操作");
    }
}

/**
 * 命令接口
 */
public interface Command {

    void execute();
}

/**
 * 具体命令类
 */
public class CopyCommand implements Command {

    private Editor editor;

    public CopyCommand(Editor editor) {
        this.editor = editor;
    }

    @Override
    public void execute() {
        editor.copy();
    }
}

public class PasteCommand implements Command {

    private Editor editor;

    public PasteCommand(Editor editor) {
        this.editor = editor;
    }

    @Override
    public void execute() {
        editor.paste();
    }
}

public class UndoCommand implements Command {

    private Editor editor;

    public UndoCommand(Editor editor) {
        this.editor = editor;
    }

    @Override
    public void execute() {
        editor.undo();
    }
}

/**
 * 调用者
 */
public class Menu {

    private Command copyCommand;
    private Command pasteCommand;
    private Command undoCommand;

    public Menu(Command copyCommand, Command pasteCommand, Command undoCommand) {
        this.copyCommand = copyCommand;
        this.pasteCommand = pasteCommand;
        this.undoCommand = undoCommand;
    }

    public void clickCopy() {
        copyCommand.execute();
    }

    public void clickPaste() {
        pasteCommand.execute();
    }

    public void clickUndo() {
        undoCommand.execute();
    }
}

public class CommandTest {

    public static void main(String[] args) {
        Editor editor = new Editor();
        Command copy = new CopyCommand(editor);
        Command paste = new PasteCommand(editor);
        Command undo = new UndoCommand(editor);

        Menu menu = new Menu(copy, paste, undo);
        menu.clickCopy();
        menu.clickPaste();
        menu.clickUndo();
    }
}

八、在JDK源码中应用命令模式的例子
1、java.lang.Runnable 和 java.util.concurrent.Callable

Runnable 和 Callable 接口是命令模式的典型例子。这两个接口封装了要在另一个线程中执行的任务,具体任务内容由 run() 方法或 call() 方法来实现,线程池或者线程的调用者在需要的时候执行这些任务。

(1)命令模式结构

  1. 命令接口:Runnable 和 Callable 是命令接口,定义了 run() 和 call() 方法,表示要执行的命令。
  2. 具体命令:任何实现 Runnable 或 Callable 的类都是具体命令类,封装了实际的任务逻辑。
  3. 调用者:Thread 或线程池(如 ExecutorService),负责触发命令的执行。

Runnable 的 run() 方法是命令的执行逻辑,而 Thread 是调用者,它负责在合适的时间触发 run() 的执行。

(2)代码示例

public class CommandExample {
    public static void main(String[] args) {
        // 创建一个命令(Runnable任务)
        Runnable command = new Runnable() {
            @Override
            public void run() {
                System.out.println("执行命令: 线程中的任务");
            }
        };
        
        // 调用者:Thread 执行命令
        Thread thread = new Thread(command);
        thread.start();
    }
}

2、javax.swing.Action

在 Swing 框架中,Action 接口用于封装行为,它是典型的命令模式。Action 可以被 JButton、JMenuItem 等组件复用,从而将动作的定义与其使用解耦。

(1)命令模式结构

  • 命令接口:Action 接口。
  • 具体命令:实现 Action 接口的具体动作类,定义 actionPerformed(ActionEvent e) 方法,封装了执行逻辑。
  • 调用者:Swing 组件,如 JButton 或 JMenuItem,这些组件触发 Action 的执行。

(2)代码示例

sayHelloAction 是命令,JButton 是调用者,点击按钮会触发 actionPerformed 方法的执行。

import javax.swing.*;
import java.awt.event.ActionEvent;

public class SwingCommandExample {
    public static void main(String[] args) {
        // 创建一个具体命令(Action)
        Action sayHelloAction = new AbstractAction("Say Hello") {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Hello, World!");
            }
        };
        
        // 调用者:JButton,触发命令的执行
        JButton button = new JButton(sayHelloAction);
        
        // 创建一个简单的Swing窗口
        JFrame frame = new JFrame("Command Pattern Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(button);
        frame.pack();
        frame.setVisible(true);
    }
}

3、java.util.Timer 和 java.util.TimerTask

TimerTask 是 JDK 中另一个典型的命令模式实现。TimerTask 类实现了 Runnable 接口,其 run() 方法封装了定时要执行的任务,Timer 类负责调度这些任务的执行。

(1)命令模式结构

  • 命令接口:TimerTask 是具体命令类,封装了任务逻辑。
  • 调用者:Timer,负责在指定时间触发命令。

(2)代码示例

TimerTask 的 run() 方法是封装的任务逻辑,Timer 是负责触发任务执行的调用者。

import java.util.Timer;
import java.util.TimerTask;

public class TimerCommandExample {
    public static void main(String[] args) {
        // 创建一个定时器
        Timer timer = new Timer();

        // 创建一个具体命令(TimerTask)
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("执行定时任务");
            }
        };

        // 调用者:Timer,调度任务
        timer.schedule(task, 1000); // 1秒后执行任务
    }
}

标签:调用者,void,模式,命令,详解,Command,editor,设计模式,public
From: https://blog.csdn.net/weixin_46619605/article/details/142856983

相关文章

  • MySQL主从配置及详解
    MySQL主从配置是一种常见的数据库架构模式,旨在提高数据库的可用性、可伸缩性和数据冗余性。以下是对MySQL主从配置的详细解析及案例分析。一、MySQL主从配置详解1.配置原理MySQL主从复制基于主服务器在二进制日志(binarylog)中跟踪所有对数据库的更改(如更新、删除等)。从服务器......
  • 工厂模式应用
    前言https://www.cnblogs.com/handsometaoa/p/17025186.html代码工厂类:@ComponentpublicclassXXEventHandlerFactoryimplementsApplicationContextAware{privateApplicationContextapplicationContext;Map<Integer,XXEventHandler>handlerMap=ne......
  • Spark - [03] 资源调度模式
    题记部分 一、Local模式1.1、概述Local模式就是运行在一台计算机上的模式,通常就是用于在本机上练手和测试的。可以通过以下几种方式设置Master(1)local:所欲计算都运行在一个线程当中,没有任何并行计算,通常我们在本机执行一些测试代码,或者练手,就用这种模式。(2)local[K]:指定使......
  • 大模型存储选型 & JuiceFS 在关键环节性能详解
    从去年开始,LLM大语言模型领域发展迅速、如LLaMA、ChatGLM、Baichuan、Qwen和yi-model等基础模型(FoundationModels)的数量显著增加。众多企业也开始基于这些基础模型做post-training的相关工作,以开发特定垂直领域的模型实现应用落地。AI模型的参数规模呈指数级增长,出现了越......
  • 从模仿到创新:AI写作如何改变传统写作模式
    随着人工智能技术的飞速发展,AI写作逐渐成为内容创作领域的一股新兴力量。从最初的模仿人类写作,到如今在多个领域实现创新,AI写作正在改变着传统写作模式,为文化产业注入新的活力。本文将从以下几个方面探讨AI写作对传统写作模式的影响及其创新之路。一、AI写作的崛起:从模仿......
  • 【Java 】包装类详解:从基本概念到实战技巧
     ......
  • Flexbox弹性盒子详解
    弹性盒子模型详解Flex弹性盒子模型详解Flex布局的基本概念Flex布局的常见属性及用法1.主轴方向2.主轴换行方式3.flex-flow(分开写更好)4.主轴对齐方式5.侧轴对齐方式5.1一行的情况5.2多行的情况6.伸缩性6.1flex-basis6.2flex-grow(伸)6.3flex-shrink(缩)7.flex复......
  • Redis 完整指南:命令与原理详解
    目录1.Redis概述什么是RedisRedis应用场景2.安装与启动Redis安装步骤源代码安装使用包管理器安装(以Ubuntu为例)编译与启动命令编客户端连接3.Redis存储结构KV存储结构数据结构类型String(字符串)List(列表)Hash(哈希)Set(集合)Zset(有序集合)4.基础命令String相关......
  • 机器学习四大框架详解及实战应用:PyTorch、TensorFlow、Keras、Scikit-learn
    目录框架概述PyTorch:灵活性与研究首选TensorFlow:谷歌加持的强大生态系统Keras:简洁明了的高层APIScikit-learn:传统机器学习的必备工具实战案例图像分类实战自然语言处理实战回归问题实战各框架的对比总结选择合适的框架1.框架概述机器学习框架在开发过程中起着至......
  • Nuxt.js 应用中的 kit:compatibility 事件钩子详解
    title:Nuxt.js应用中的kit:compatibility事件钩子详解date:2024/10/11updated:2024/10/11author:cmdragonexcerpt:kit:compatibility是处理浏览器兼容性问题的有效工具。正如本篇文章中所述,合理地利用这一钩子可以提升用户体验,并确保应用在不同环境中都能稳定运行......