Java 命令模式的高阶应用与代码示例

258 阅读3分钟

在 Java 开发中,设计模式对于构建灵活、可维护的软件系统起着至关重要的作用。命令模式作为一种行为设计模式,它将请求封装成对象,从而允许你以不同的请求、队列或日志请求来参数化其他对象,并且支持可撤销操作。本文将深入探讨 Java 命令模式的高阶使用,并附上详细的代码示例。

一、命令模式基础回顾

命令模式主要涉及以下几个角色:

  • Command(命令) :声明执行操作的接口。
  • ConcreteCommand(具体命令) :实现 Command 接口,定义具体的操作逻辑,通常会持有接收者对象。
  • Receiver(接收者) :知道如何执行与请求相关的操作,任何类都可能作为接收者。
  • Invoker(调用者) :要求命令执行请求,通常会持有命令对象,可以设置和调用命令。

二、高阶应用场景

(一)宏命令

宏命令是一组命令的集合,可以一次性执行多个命令。例如,在一个图形编辑软件中,“新建文档并打开网格线” 这个操作就可以用宏命令来实现。

import java.util.ArrayList;
import java.util.List;
// 命令接口
interface Command {
    void execute();
}
// 具体命令:新建文档
class NewDocumentCommand implements Command {
    @Override
    public void execute() {
        System.out.println("新建文档");
    }
}
// 具体命令:打开网格线
class OpenGridCommand implements Command {
    @Override
    public void execute() {
        System.out.println("打开网格线");
    }
}
// 宏命令类
class MacroCommand implements Command {
    private List<Command> commands = new ArrayList<>();
    public void addCommand(Command command) {
        commands.add(command);
    }
    @Override
    public void execute() {
        for (Command command : commands) {
            command.execute();
        }
    }
}
// 测试宏命令
public class CommandPatternAdvanced {
    public static void main(String[] args) {
        MacroCommand macro = new MacroCommand();
        macro.addCommand(new NewDocumentCommand());
        macro.addCommand(new OpenGridCommand());
        macro.execute();
    }
}

(二)命令队列与线程池

在一些复杂的系统中,可能会有大量的命令需要处理。可以将命令放入队列中,然后利用线程池来并发处理这些命令,提高系统的吞吐量。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
// 定义命令接口
interface Command {
    void execute();
}
// 具体命令类示例
class PrintCommand implements Command {
    private String message;
    public PrintCommand(String message) {
        this.message = message;
    }
    @Override
    public void execute() {
        System.out.println(message);
    }
}
// 命令队列管理类
class CommandQueue {
    private BlockingQueue<Command> queue = new LinkedBlockingQueue<>();
    private ExecutorService executorService = Executors.newFixedThreadPool(5);
    public void addCommand(Command command) {
        try {
            queue.put(command);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    public void startProcessing() {
        while (true) {
            try {
                Command command = queue.take();
                executorService.submit(() -> command.execute());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}
// 测试命令队列与线程池
public class CommandQueueExample {
    public static void main(String[] args) {
        CommandQueue queue = new CommandQueue();
        queue.addCommand(new PrintCommand("命令 1"));
        queue.addCommand(new PrintCommand("命令 2"));
        queue.addCommand(new PrintCommand("命令 3"));
        new Thread(() -> queue.startProcessing()).start();
    }
}

(三)命令的撤销与重做

在一些应用场景中,如文本编辑器的编辑操作,需要支持撤销和重做功能。可以通过在命令对象中记录操作的状态来实现。

import java.util.Stack;
// 命令接口,增加撤销和重做方法
interface UndoableCommand {
    void execute();
    void undo();
    void redo();
}
// 具体命令:文本插入命令
class InsertTextCommand implements UndoableCommand {
    private StringBuilder text;
    private int index;
    private String insertedText;
    private boolean executed = false;
    public InsertTextCommand(StringBuilder text, int index, String insertedText) {
        this.text = text;
        this.index = index;
        this.insertedText = insertedText;
    }
    @Override
    public void execute() {
        text.insert(index, insertedText);
        executed = true;
    }
    @Override
    public void undo() {
        if (executed) {
            int startIndex = index;
            int endIndex = index + insertedText.length();
            text.delete(startIndex, endIndex);
            executed = false;
        }
    }
    @Override
    public void redo() {
        if (!executed) {
            text.insert(index, insertedText);
            executed = true;
        }
    }
}
// 命令管理类,用于管理撤销和重做操作
class CommandManager {
    private Stack<UndoableCommand> undoStack = new Stack<>();
    private Stack<UndoableCommand> redoStack = new Stack<>();
    public void executeCommand(UndoableCommand command) {
        command.execute();
        undoStack.push(command);
        redoStack.clear();
    }
    public void undo() {
        if (!undoStack.isEmpty()) {
            UndoableCommand command = undoStack.pop();
            command.undo();
            redoStack.push(command);
        }
    }
    public void redo() {
        if (!redoStack.isEmpty()) {
            UndoableCommand command = redoStack.pop();
            command.redo();
            undoStack.push(command);
        }
    }
}
// 测试撤销与重做功能
public class UndoRedoCommandExample {
    public static void main(String[] args) {
        StringBuilder text = new StringBuilder("初始文本");
        CommandManager manager = new CommandManager();
        // 插入命令
        InsertTextCommand insertCommand1 = new InsertTextCommand(text, 4, "新的");
        manager.executeCommand(insertCommand1);
        System.out.println(text);
        // 再次插入命令
        InsertTextCommand insertCommand2 = new InsertTextCommand(text, 8, "内容");
        manager.executeCommand(insertCommand2);
        System.out.println(text);
        // 撤销操作
        manager.undo();
        System.out.println(text);
        // 重做操作
        manager.redo();
        System.out.println(text);
    }
}

通过上述高阶应用场景的介绍和代码示例,可以看到命令模式在 Java 开发中的强大之处。它能够有效地解耦请求发送者与接收者,并且通过灵活的组合与扩展,满足各种复杂的业务需求,提高软件系统的可维护性与可扩展性。在实际开发中,开发者可以根据具体的业务场景,巧妙地运用命令模式来构建更加优雅、高效的 Java 应用程序。