# 命令模式
命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而使你可以用不同的请求对客户进行参数化。这个模式也支持可撤销的操作。
# 命令模式的主要角色
- 命令接口(Command Interface):定义了一个执行操作的接口。
- 具体命令类(Concrete Command Class):实现了命令接口,并持有接收者对象的引用,负责调用接收者的相应方法来执行请求。
- 接收者(Receiver Class):知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
- 调用者(Invoker Class):要求该命令执行这个请求。
- 客户端(Client):创建一个具体命令对象并设定它的接收者。
# 示例
以下是一个使用命令模式的 JavaScript 编辑器示例:
// 接收者类(编辑器)
class Editor {
constructor() {
this.content = [];
this.history = [];
this.future = [];
}
insert(text, position) {
if (position === null || position < 0) {
this.content.push(...text.split(''));
} else {
const before = this.content.slice(0, position);
const after = this.content.slice(position);
this.content = [...before, ...text.split(''), ...after];
}
this.history.push({ type: 'insert', text, position });
this.future = [];
}
remove(position, length) {
const before = this.content.slice(0, position);
const after = this.content.slice(position + length);
const removedText = this.content.slice(position, position + length).join('');
this.content = [...before, ...after];
this.history.push({ type: 'remove', position, length, text: removedText });
this.future = [];
}
getContent() {
return this.content.join('');
}
}
// 具体命令类(插入文本命令)
class InsertCommand {
constructor(editor, text, position) {
this.editor = editor;
this.text = text.split('');
this.position = position;
}
execute() {
this.editor.insert(this.text.join(''), this.position);
}
undo() {
this.editor.remove(this.position, this.text.length);
}
}
// 具体命令类(删除文本命令)
class RemoveCommand {
constructor(editor, position, length) {
this.editor = editor;
this.position = position;
this.length = length;
}
execute() {
this.editor.remove(this.position, this.length);
}
undo() {
this.editor.insert(this.text, this.position);
}
}
// 调用者类(编辑器界面)
class EditorInterface {
constructor(editor) {
this.editor = editor;
}
insert(text, position) {
const command = new InsertCommand(this.editor, text, position);
command.execute();
}
remove(position, length) {
const command = new RemoveCommand(this.editor, position, length);
command.execute();
}
undo() {
if (this.editor.history.length === 0) return;
const action = this.editor.history.pop();
if (action.type === 'insert') {
const command = new RemoveCommand(this.editor, action.position, action.text.length);
command.undo();
} else if (action.type === 'remove') {
const command = new InsertCommand(this.editor, action.text, action.position);
command.undo();
}
}
redo() {
// 可以在这里实现重做逻辑
}
}
// 客户端代码
const editor = new Editor();
const editorInterface = new EditorInterface(editor);
editorInterface.insert('Hello, ', 0); // 输出: Hello,
editorInterface.insert('World!', 13); // 输出: Hello, World!
console.log(editor.getContent()); // 输出: Hello, World!
editorInterface.undo(); // 输出: Hello,
console.log(editor.getContent()); // 输出: Hello,
editorInterface.redo(); // 输出: Hello, World!
console.log(editor.getContent()); // 输出: Hello, World!
# 命令模式的优势和适用场景
优点:
- 将请求的发起者和接收者解耦,使得代码更灵活和可扩展。
- 支持撤销和重做操作。
- 可以将命令记录在日志中,便于追踪和审计。
适用场景:
- 需要将请求封装成对象,并延迟执行或进行参数化。
- 需要支持队列和日志功能。
- 需要实现可撤销的操作。
- 需要解耦调用者和接收者之间的关系。
# 总结
通过使用命令模式,可以将请求的发起者和接收者解耦,并通过一个中介者(即命令对象)来传递请求。这使得代码更灵活、可扩展,并且支持撤销和重做操作等高级功能。