为了在命令模式的基础上实现打消(Undo)和回退(Redo)功能,我们可以在每个命令类中记载一些必要的状态,允许我们打消之前的操纵,并在必要时回退操纵。常见的做法是使用一个命令堆栈来存储历史命令,并为每个命令提供打消(undo)操纵。
我们可以通过以下步骤来添加打消和回退功能:
- Command接口:为命令接口添加一个undo()方法。
- 详细命令类(ConcreteCommand):为每个详细命令类实现undo()方法,打消相应的操纵。
- Invoker类:管理一个命令堆栈(历史记载),并实现undo()和redo()方法来实行打消和回退操纵。
代码实现:
我们将对之前的代码进行修改,来实现打消和回退功能:
- #include <iostream>
- #include <memory>
- #include <vector>
- #include <stack>
- // 绘图命令接口
- class Command {
- public:
- virtual ~Command() = default;
- virtual void execute() = 0;
- virtual void undo() = 0; // 增加撤销操作接口
- };
- // 接收者:绘图工具(如画布)
- class Receiver {
- public:
- void drawPoint(int x, int y) {
- std::cout << "Drawing point at (" << x << ", " << y << ").\n";
- }
- void undoDrawPoint(int x, int y) {
- std::cout << "Undo drawing point at (" << x << ", " << y << ").\n";
- }
- void drawLine(int x1, int y1, int x2, int y2) {
- std::cout << "Drawing line from (" << x1 << ", " << y1 << ") to (" << x2 << ", " << y2 << ").\n";
- }
- void undoDrawLine(int x1, int y1, int x2, int y2) {
- std::cout << "Undo drawing line from (" << x1 << ", " << y1 << ") to (" << x2 << ", " << y2 << ").\n";
- }
- void drawCircle(int x, int y, int radius) {
- std::cout << "Drawing circle at (" << x << ", " << y << ") with radius " << radius << ".\n";
- }
- void undoDrawCircle(int x, int y, int radius) {
- std::cout << "Undo drawing circle at (" << x << ", " << y << ") with radius " << radius << ".\n";
- }
- void drawEllipse(int x, int y, int majorAxis, int minorAxis) {
- std::cout << "Drawing ellipse at (" << x << ", " << y << ") with major axis " << majorAxis << " and minor axis " << minorAxis << ".\n";
- }
- void undoDrawEllipse(int x, int y, int majorAxis, int minorAxis) {
- std::cout << "Undo drawing ellipse at (" << x << ", " << y << ") with major axis " << majorAxis << " and minor axis " << minorAxis << ".\n";
- }
- void drawPolyline(const std::vector<std::pair<int, int>>& points) {
- std::cout << "Drawing polyline with the following points:\n";
- for (const auto& point : points) {
- std::cout << "(" << point.first << ", " << point.second << ") ";
- }
- std::cout << "\n";
- }
- void undoDrawPolyline(const std::vector<std::pair<int, int>>& points) {
- std::cout << "Undo drawing polyline with the following points:\n";
- for (const auto& point : points) {
- std::cout << "(" << point.first << ", " << point.second << ") ";
- }
- std::cout << "\n";
- }
- };
- // 绘制点的命令
- class DrawPointCommand : public Command {
- private:
- Receiver* receiver;
- int x, y;
- public:
- DrawPointCommand(Receiver* r, int x, int y) : receiver(r), x(x), y(y) {}
-
- void execute() override {
- receiver->drawPoint(x, y);
- }
- void undo() override {
- receiver->undoDrawPoint(x, y);
- }
- };
- // 绘制直线的命令
- class DrawLineCommand : public Command {
- private:
- Receiver* receiver;
- int x1, y1, x2, y2;
- public:
- DrawLineCommand(Receiver* r, int x1, int y1, int x2, int y2) : receiver(r), x1(x1), y1(y1), x2(x2), y2(y2) {}
- void execute() override {
- receiver->drawLine(x1, y1, x2, y2);
- }
- void undo() override {
- receiver->undoDrawLine(x1, y1, x2, y2);
- }
- };
- // 绘制圆形的命令
- class DrawCircleCommand : public Command {
- private:
- Receiver* receiver;
- int x, y, radius;
- public:
- DrawCircleCommand(Receiver* r, int x, int y, int radius) : receiver(r), x(x), y(y), radius(radius) {}
- void execute() override {
- receiver->drawCircle(x, y, radius);
- }
- void undo() override {
- receiver->undoDrawCircle(x, y, radius);
- }
- };
- // 绘制椭圆的命令
- class DrawEllipseCommand : public Command {
- private:
- Receiver* receiver;
- int x, y, majorAxis, minorAxis;
- public:
- DrawEllipseCommand(Receiver* r, int x, int y, int majorAxis, int minorAxis)
- : receiver(r), x(x), y(y), majorAxis(majorAxis), minorAxis(minorAxis) {}
- void execute() override {
- receiver->drawEllipse(x, y, majorAxis, minorAxis);
- }
- void undo() override {
- receiver->undoDrawEllipse(x, y, majorAxis, minorAxis);
- }
- };
- // 绘制多段线的命令
- class DrawPolylineCommand : public Command {
- private:
- Receiver* receiver;
- std::vector<std::pair<int, int>> points;
- public:
- DrawPolylineCommand(Receiver* r, const std::vector<std::pair<int, int>>& points)
- : receiver(r), points(points) {}
- void execute() override {
- receiver->drawPolyline(points);
- }
- void undo() override {
- receiver->undoDrawPolyline(points);
- }
- };
- // 调用者:工具栏或按钮
- class Invoker {
- private:
- std::stack<std::shared_ptr<Command>> commandHistory; // 历史命令栈
- std::stack<std::shared_ptr<Command>> redoStack; // 重做命令栈
- public:
- void executeCommand(std::shared_ptr<Command> cmd) {
- cmd->execute();
- commandHistory.push(cmd); // 将命令压入历史栈
- while (!redoStack.empty()) { // 清空重做栈
- redoStack.pop();
- }
- }
- void undo() {
- if (!commandHistory.empty()) {
- std::shared_ptr<Command> cmd = commandHistory.top();
- commandHistory.pop();
- cmd->undo();
- redoStack.push(cmd); // 将撤销的命令压入重做栈
- } else {
- std::cout << "No command to undo.\n";
- }
- }
- void redo() {
- if (!redoStack.empty()) {
- std::shared_ptr<Command> cmd = redoStack.top();
- redoStack.pop();
- cmd->execute();
- commandHistory.push(cmd); // 将重做的命令压入历史栈
- } else {
- std::cout << "No command to redo.\n";
- }
- }
- };
- // 客户端代码
- int main() {
- Receiver receiver; // 绘图工具(画布)
- // 创建具体的命令
- std::shared_ptr<Command> drawPoint = std::make_shared<DrawPointCommand>(&receiver, 10, 20);
- std::shared_ptr<Command> drawLine = std::make_shared<DrawLineCommand>(&receiver, 10, 20, 30, 40);
- std::shared_ptr<Command> drawCircle = std::make_shared<DrawCircleCommand>(&receiver, 50, 50, 15);
- std::shared_ptr<Command> drawEllipse = std::make_shared<DrawEllipseCommand>(&receiver, 70, 70, 20, 10);
- std::vector<std::pair<int, int>> polylinePoints = {{10, 10}, {20, 20}, {30, 30}, {40, 40}};
- std::shared_ptr<Command> drawPolyline = std::make_shared<DrawPolylineCommand>(&receiver, polylinePoints);
- // 创建调用者
- Invoker invoker;
- // 模拟用户操作,通过调用命令绘制图形
- invoker.executeCommand(drawPoint);
- invoker.executeCommand(drawLine);
- invoker.executeCommand(drawCircle);
- invoker.executeCommand(drawEllipse);
- invoker.executeCommand(drawPolyline);
- // 撤销操作
- std::cout << "\nUndoing the last command:\n";
- invoker.undo();
- // 回退(重
- 做)操作
- std::cout << "\nRedoing the last undone command:\n";
- invoker.redo();
- return 0;
- }
复制代码 关键修改:
- Command接口:添加了undo()方法,使每个命令都能打消其操纵。
- Receiver类:为每个绘制方法添加了打消方法(undoDraw...),用于打消详细的图形操纵。
- Invoker类:管理两个栈——commandHistory(历史命令栈)和redoStack(重做命令栈)。在实行命令时将其压入commandHistory,在打消时将命令从commandHistory中取出并实行undo(),同时将命令压入redoStack。回退时从redoStack取出命令并重新实行。
输出:
- Drawing point at (10, 20).
- Drawing line from (10, 20) to (30, 40).
- Drawing circle at (50, 50) with radius 15.
- Drawing ellipse at (70, 70) with major axis 20 and minor axis 10.
- Drawing polyline with the following points:
- (10, 10) (20, 20) (30, 30) (40, 40)
- Undoing the last command:
- Undo drawing polyline with the following points:
- (10, 10) (20, 20) (30, 30) (40, 40)
- Redoing the last undone command:
- Drawing polyline with the following points:
- (10, 10) (20, 20) (30, 30) (40, 40)
复制代码 功能扩展:
- 打消操纵:允许打消最后的绘图命令。
- 回退操纵:允许重做之前打消的命令。
这样,我们就实现了打消和回退功能,用户可以随时打消之前的操纵并规复它们。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |