Java命令模式源码剖析及使用场景

2024-03-15 1592阅读

温馨提示:这篇文章已超过426天没有更新,请注意相关的内容是否还可用!

命令模式

  • 一、原理与通俗理解
  • 二、项目开发日志功能
  • 三、Java源码中的命令模式
  • 四、总结优缺点以及使用经验

    一、原理与通俗理解

    命令模式将请求封装为一个命令对象,将发出请求的对象与执行请求的对象解耦。命令模式可以让你在不同时间点调用命令,将命令放入队列中,并实现对命令的撤销和恢复操作。

    Java命令模式源码剖析及使用场景
    (图片来源网络,侵删)

    比如在餐馆点餐,你(调用者)跟服务员(调用对象)说要来一份炒饭(命令),服务员就去通知厨师(执行对象)去炒一份炒饭。

    二、项目开发日志功能

    需求:记录日志并支持撤销操作

    实现:

    1. 定义命令接口Command,定义执行命令、撤销命令方法
    2. LogCommand 类实现了具体的日志记录命令,记录日志时备份当前日志,并在撤销时恢复到备份的日志状态。
    3. LogCommandInvoker 类负责执行和管理命令,执行命令时记录历史记录,并且支持撤销操作。
    4. LogManager 类负责实际的日志记录操作,包括记录日志、获取当前日志内容以及清空日志。
    // 1. 定义命令接口
    interface Command {
        void execute(); // 执行命令
        void undo(); // 撤销命令
    }
    // 2. 实现具体的日志记录命令
    class LogCommand implements Command {
        private LogManager logManager;
        private String logMessage;
        private String backupLog; // 用于撤销操作
        public LogCommand(LogManager logManager, String logMessage) {
            this.logManager = logManager;
            this.logMessage = logMessage;
        }
        @Override
        public void execute() {
            backupLog = logManager.getLog(); // 备份当前日志
            logManager.log(logMessage); // 记录新日志
        }
        @Override
        public void undo() {
            logManager.clearLog(); // 清空当前日志
            logManager.log(backupLog); // 恢复到执行之前的日志
        }
    }
    // 3. 定义命令调用者
    class LogCommandInvoker {
        private List commandHistory = new ArrayList();
        public void executeCommand(Command command) {
            command.execute(); // 执行命令
            commandHistory.add(command); // 将命令添加到历史记录中
        }
        public void undoCommand() {
            if (!commandHistory.isEmpty()) {
                Command command = commandHistory.remove(commandHistory.size() - 1); // 从历史记录中取出最后一个命令
                command.undo(); // 执行撤销操作
            }
        }
    }
    // 4. 定义命令执行者
    class LogManager {
        private StringBuilder log = new StringBuilder();
        public void log(String message) {
            log.append(message).append("\n"); // 记录日志信息
            System.out.println("Logged: " + message);
        }
        public String getLog() {
            return log.toString(); // 获取当前日志内容
        }
        public void clearLog() {
            log = new StringBuilder(); // 清空日志
        }
    }
    

    使用:

    LogManager logManager = new LogManager();
    LogCommandInvoker invoker = new LogCommandInvoker();
    // 记录日志
    invoker.executeCommand(new LogCommand(logManager, "Log message 1"));
    invoker.executeCommand(new LogCommand(logManager, "Log message 2"));
    // 撤销一条日志
    invoker.undoCommand();
    // 再次记录日志
    invoker.executeCommand(new LogCommand(logManager, "Log message 3"));
    

    三、Java源码中的命令模式

    1. java.lang.Runnable

    Runnable接口允许将一个命令封装为一个可执行的对象,然后可以将该对象传递给线程执行。

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            // 执行命令
        }
    });
    thread.start();
    

    首先,我们来看一下Runnable接口的定义,这是一个简单的函数式接口,只有一个抽象方法run()。

    public interface Runnable {
        public abstract void run();
    }
    

    现在我们创建一个类来实现Runnable接口:

    public class MyCommand implements Runnable {
        @Override
        public void run() {
            // 执行具体的任务
            System.out.println("Executing command");
        }
    }
    

    现在我们可以创建一个线程并将MyCommand对象作为参数传递给线程:

    public class Main {
        public static void main(String[] args) {
            MyCommand command = new MyCommand();
            Thread thread = new Thread(command);
            thread.start();  // 启动线程,调用command的run()方法
        }
    }
    

    在上面的例子中,MyCommand对象封装了需要被执行的任务,并且通过将其作为参数传递给线程,线程会调用其run()方法来执行具体的任务。这就是命令模式的应用,将操作封装成对象,并且能够在不同的上下文中执行这个命令。

    因此,通过实现Runnable接口并重写run()方法,可以实现类似于命令模式的效果,封装命令并且能够在不同的上下文中执行。

    四、总结优缺点以及使用经验

    优点:

    1. 低耦合,命令发送者和执行者完全解耦
    2. 可以将命令存入队列,实现撤销/恢复操作
    3. 命令对象可以携带额外的执行信息
    4. 新增新命令非常方便,无需修改现有代码

    缺点:

    1. 可能会导致系统有过多的具体命令类
    2. 命令对象本身冗长

    使用经验:

    1. 适用于需要将操作请求作为对象进行参数化传递的场景
    2. 适用于需要支持命令队列、命令记录日志、撤销/恢复操作等功能的场景
    3. 可以考虑使用组合模式组合多个命令形成复合命令
    4. 在设计阶段就应该考虑是否需要支持撤销/恢复操作
    5. 命令模式可以为不同对象的相同操作提供统一的接口
    6. 在面向对象设计中,命令模式是常用的行为型设计模式

    命令模式将请求与执行解耦,可以方便地扩展新的命令、实现命令队列和支持撤销/恢复操作等功能。在需要对操作进行参数化、队列化、日志记录、撤销/恢复等需求时,命令模式是一个不错的选择。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]