设计模式之命令模式

发布于:2025-07-06 ⋅ 阅读:(18) ⋅ 点赞:(0)

定义

       命令模式(Command Pattern)‌ 是一种行为型设计模式,核心思想是将‌请求封装为独立对象‌(命令对象),使请求的发送者与接收者解耦。其关键特性包括:
       1)‌请求对象化‌:将操作(如“打开文件”“撤销操作”)封装成包含执行方法的独立对象‌。
       2)‌调用者与执行者分离‌:调用者(Invoker)只需调用命令对象的统一接口,无需知晓具体执行细节‌。
       3)‌支持扩展操作‌:新增命令无需修改现有代码,符合开闭原则

结构

在这里插入图片描述

适用场景

       1)需要参数化请求的场景,根据不同参数触发不同操作。
       2)需要支持事务/撤销操作的场景,记录操作历史以便回滚。

使用示例

       文本编辑器撤销功能。
       定义命令接口

/**
 * 命令接口(抽象命令)
 */
public interface Command {

    void execute();

    void undo();

}

       定义具体命令

/**
 * 具体命令:文本输入命令
 */
public class InsertCommand implements Command {

    private StringBuilder receiver; // 接收者:文本内容

    private String text;            // 操作的文本

    private int position;           // 插入位置

    public InsertCommand(StringBuilder sb, String text, int pos) {
        this.receiver = sb;
        this.text = text;
        this.position = pos;
    }

    @Override
    public void execute() {
        receiver.insert(position, text); // 执行插入
    }

    @Override
    public void undo() {
        receiver.delete(position, position + text.length()); // 撤销:删除插入的文本
    }

}

       定义命令历史

import java.util.Stack;

public class CommandHistory {
    private Stack<Command> undoStack = new Stack<>();
    private Stack<Command> redoStack = new Stack<>();

    // 记录新执行的命令
    public void push(Command cmd) {
        undoStack.push(cmd);
        redoStack.clear(); // 新命令使重做栈失效
    }

    // 撤销最近操作
    public boolean undo() {
        if (!undoStack.isEmpty()) {
            Command cmd = undoStack.pop();
            cmd.undo();
            redoStack.push(cmd);
            return true;
        }
        return false;
    }

    // 重做最近撤销的操作
    public boolean redo() {
        if (!redoStack.isEmpty()) {
            Command cmd = redoStack.pop();
            cmd.execute();
            undoStack.push(cmd);
            return true;
        }
        return false;
    }

    // 清空历史记录
    public void clear() {
        undoStack.clear();
        redoStack.clear();
    }
}

       定义调用者

/**
 * 调用者(Invoker):编辑器界面按钮
 * receiver 由java自带的StringBuilder担当
 */
public class EditorButton {

    private Command command;

    private CommandHistory history;

    public EditorButton(CommandHistory history) {
        this.history = history;
    }

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

    public void onClick() {
        command.execute(); // 执行命令
        history.push(command); // 存入历史栈
    }

}

       测试

public class Client {

    public static void main(String[] args) {
        StringBuilder textContent = new StringBuilder("Hello"); // 接收者:文本内容
        CommandHistory history = new CommandHistory();
        EditorButton insertBtn = new EditorButton(history);

        // 创建命令:在位置5插入" World!"
        insertBtn.setCommand(new InsertCommand(textContent, " World!", 5));
        insertBtn.onClick(); // 执行 → 文本变为"Hello World!"
        System.out.println(textContent);

        history.undo(); // 撤销 → 文本恢复为"Hello"
        System.out.println(textContent);
    }

}

网站公告

今日签到

点亮在社区的每一天
去签到