命令模式
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 94 课,共 110 课。
命令模式将请求封装为对象,让你可以用不同的请求对客户端进行参数化、将操作加入队列,或支持撤销功能。你不再直接调用方法,而是将操作包装在命令对象中,以便存储、传递或稍后执行。
该模式包含三个关键组件:带有 execute 方法的 Command 接口、实现特定操作的具体命令,以及执行实际工作的接收者。你还可以选择使用调用者来触发命令,而无需了解命令的具体作用:
abstract class Command {
void execute();
}
class Light {
void turnOn() => print('Light is ON');
void turnOff() => print('Light is OFF');
}
class TurnOnCommand implements Command {
final Light light;
TurnOnCommand(this.light);
@override
void execute() => light.turnOn();
}
class TurnOffCommand implements Command {
final Light light;
TurnOffCommand(this.light);
@override
void execute() => light.turnOff();
}
class RemoteControl {
Command? _command;
void setCommand(Command command) {
_command = command;
}
void pressButton() {
_command?.execute();
}
}
void main() {
var light = Light();
var remote = RemoteControl();
remote.setCommand(TurnOnCommand(light));
remote.pressButton(); // 灯已打开
remote.setCommand(TurnOffCommand(light));
remote.pressButton(); // 灯已关闭
}RemoteControl 对灯一无所知,它只会执行收到的命令。这种解耦让你可以轻松添加新命令,而无需修改调用者。命令模式非常适合实现撤销/重做系统、任务队列或宏录制,因为在这些场景中,你需要将操作视为一等对象。
挑战
简单让我们使用命令模式构建一个文本编辑器命令系统!你将创建一个系统,把文本操作封装为命令对象,让编辑器无需了解每种操作的具体细节,就能执行不同的操作。这是命令模式的经典应用场景,你可以把它想象成一个撤销/重做系统,其中每个操作都存储为一个对象。
你将把代码分成两个文件:
commands.dart:在这里创建命令系统。先创建一个抽象类Command,并声明一个execute()方法。然后创建一个TextDocument类(接收者),它包含一个String content字段(初始为空),并有三个方法:append(String text):在内容末尾添加文本clear():将内容设为空字符串show():打印Document: [content]
TextDocument的具体命令:AppendCommand:构造函数接收文档和文本,执行时添加文本ClearCommand:构造函数接收文档,执行时清空文档ShowCommand:构造函数接收文档,执行时显示文档内容
TextEditor类(调用者),用于存储命令列表。它应该有一个addCommand(Command command)方法,用于将命令加入队列;还应该有一个runAll()方法,按顺序执行队列中的所有命令。main.dart:导入命令文件,并演示命令模式。创建一个TextDocument和一个TextEditor。按顺序将以下命令加入队列:添加Hello,添加World,显示文档,添加!,再次显示,清空文档,最后再显示一次。然后运行队列中的所有命令。
注意,TextEditor 不知道添加、清空或显示的具体操作,它只负责执行交给它的命令。这种解耦正是命令模式的核心!
预期输出:
Document: Hello World
Document: Hello World!
Document: 亲手试试
import 'commands.dart';
void main() {
// TODO:创建一个 TextDocument 实例
// TODO:创建一个 TextEditor 实例
// TODO:按顺序将以下命令加入队列:
// 1. 追加 "Hello"
// 2. 追加 " World"
// 3. 显示文档
// 4. 追加 "!"
// 5. 再次显示文档
// 6. 清空文档
// 7. 最后显示一次文档
// TODO:运行所有已加入队列的命令
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器