跳到主要内容

命令模式

问题

Rust 中命令模式如何实现?典型应用场景是什么?

答案

命令模式将操作封装为对象,支持撤销/重做、队列化、日志记录。

实现:文本编辑器撤销/重做

trait Command {
fn execute(&mut self, doc: &mut String);
fn undo(&mut self, doc: &mut String);
}

struct InsertText {
position: usize,
text: String,
}

impl Command for InsertText {
fn execute(&mut self, doc: &mut String) {
doc.insert_str(self.position, &self.text);
}

fn undo(&mut self, doc: &mut String) {
let end = self.position + self.text.len();
doc.replace_range(self.position..end, "");
}
}

struct DeleteText {
position: usize,
length: usize,
deleted: String, // 保存被删除的文本用于 undo
}

impl Command for DeleteText {
fn execute(&mut self, doc: &mut String) {
self.deleted = doc[self.position..self.position + self.length].to_string();
doc.replace_range(self.position..self.position + self.length, "");
}

fn undo(&mut self, doc: &mut String) {
doc.insert_str(self.position, &self.deleted);
}
}

// 命令管理器
struct Editor {
document: String,
history: Vec<Box<dyn Command>>,
redo_stack: Vec<Box<dyn Command>>,
}

impl Editor {
fn execute(&mut self, mut cmd: Box<dyn Command>) {
cmd.execute(&mut self.document);
self.history.push(cmd);
self.redo_stack.clear();
}

fn undo(&mut self) {
if let Some(mut cmd) = self.history.pop() {
cmd.undo(&mut self.document);
self.redo_stack.push(cmd);
}
}

fn redo(&mut self) {
if let Some(mut cmd) = self.redo_stack.pop() {
cmd.execute(&mut self.document);
self.history.push(cmd);
}
}
}

常见面试问题

Q1: 命令模式在哪些场景下有用?

答案

场景说明
撤销/重做编辑器、画板、表单
任务队列异步执行、延迟执行
宏命令批量操作
事务日志操作记录与回放

相关链接