以绘图(绘制点、直线、圆、椭圆、多段线)为例子 通过设计模式中的命令模 ...

打印 上一主题 下一主题

主题 826|帖子 826|积分 2478

为了在命令模式的基础上实现打消(Undo)和回退(Redo)功能,我们可以在每个命令类中记载一些必要的状态,允许我们打消之前的操纵,并在必要时回退操纵。常见的做法是使用一个命令堆栈来存储历史命令,并为每个命令提供打消(undo)操纵。
我们可以通过以下步骤来添加打消和回退功能:

  • Command接口:为命令接口添加一个undo()方法。
  • 详细命令类(ConcreteCommand):为每个详细命令类实现undo()方法,打消相应的操纵。
  • Invoker类:管理一个命令堆栈(历史记载),并实现undo()和redo()方法来实行打消和回退操纵。
代码实现:

我们将对之前的代码进行修改,来实现打消和回退功能:
  1. #include <iostream>
  2. #include <memory>
  3. #include <vector>
  4. #include <stack>
  5. // 绘图命令接口
  6. class Command {
  7. public:
  8.     virtual ~Command() = default;
  9.     virtual void execute() = 0;
  10.     virtual void undo() = 0;  // 增加撤销操作接口
  11. };
  12. // 接收者:绘图工具(如画布)
  13. class Receiver {
  14. public:
  15.     void drawPoint(int x, int y) {
  16.         std::cout << "Drawing point at (" << x << ", " << y << ").\n";
  17.     }
  18.     void undoDrawPoint(int x, int y) {
  19.         std::cout << "Undo drawing point at (" << x << ", " << y << ").\n";
  20.     }
  21.     void drawLine(int x1, int y1, int x2, int y2) {
  22.         std::cout << "Drawing line from (" << x1 << ", " << y1 << ") to (" << x2 << ", " << y2 << ").\n";
  23.     }
  24.     void undoDrawLine(int x1, int y1, int x2, int y2) {
  25.         std::cout << "Undo drawing line from (" << x1 << ", " << y1 << ") to (" << x2 << ", " << y2 << ").\n";
  26.     }
  27.     void drawCircle(int x, int y, int radius) {
  28.         std::cout << "Drawing circle at (" << x << ", " << y << ") with radius " << radius << ".\n";
  29.     }
  30.     void undoDrawCircle(int x, int y, int radius) {
  31.         std::cout << "Undo drawing circle at (" << x << ", " << y << ") with radius " << radius << ".\n";
  32.     }
  33.     void drawEllipse(int x, int y, int majorAxis, int minorAxis) {
  34.         std::cout << "Drawing ellipse at (" << x << ", " << y << ") with major axis " << majorAxis << " and minor axis " << minorAxis << ".\n";
  35.     }
  36.     void undoDrawEllipse(int x, int y, int majorAxis, int minorAxis) {
  37.         std::cout << "Undo drawing ellipse at (" << x << ", " << y << ") with major axis " << majorAxis << " and minor axis " << minorAxis << ".\n";
  38.     }
  39.     void drawPolyline(const std::vector<std::pair<int, int>>& points) {
  40.         std::cout << "Drawing polyline with the following points:\n";
  41.         for (const auto& point : points) {
  42.             std::cout << "(" << point.first << ", " << point.second << ") ";
  43.         }
  44.         std::cout << "\n";
  45.     }
  46.     void undoDrawPolyline(const std::vector<std::pair<int, int>>& points) {
  47.         std::cout << "Undo drawing polyline with the following points:\n";
  48.         for (const auto& point : points) {
  49.             std::cout << "(" << point.first << ", " << point.second << ") ";
  50.         }
  51.         std::cout << "\n";
  52.     }
  53. };
  54. // 绘制点的命令
  55. class DrawPointCommand : public Command {
  56. private:
  57.     Receiver* receiver;
  58.     int x, y;
  59. public:
  60.     DrawPointCommand(Receiver* r, int x, int y) : receiver(r), x(x), y(y) {}
  61.    
  62.     void execute() override {
  63.         receiver->drawPoint(x, y);
  64.     }
  65.     void undo() override {
  66.         receiver->undoDrawPoint(x, y);
  67.     }
  68. };
  69. // 绘制直线的命令
  70. class DrawLineCommand : public Command {
  71. private:
  72.     Receiver* receiver;
  73.     int x1, y1, x2, y2;
  74. public:
  75.     DrawLineCommand(Receiver* r, int x1, int y1, int x2, int y2) : receiver(r), x1(x1), y1(y1), x2(x2), y2(y2) {}
  76.     void execute() override {
  77.         receiver->drawLine(x1, y1, x2, y2);
  78.     }
  79.     void undo() override {
  80.         receiver->undoDrawLine(x1, y1, x2, y2);
  81.     }
  82. };
  83. // 绘制圆形的命令
  84. class DrawCircleCommand : public Command {
  85. private:
  86.     Receiver* receiver;
  87.     int x, y, radius;
  88. public:
  89.     DrawCircleCommand(Receiver* r, int x, int y, int radius) : receiver(r), x(x), y(y), radius(radius) {}
  90.     void execute() override {
  91.         receiver->drawCircle(x, y, radius);
  92.     }
  93.     void undo() override {
  94.         receiver->undoDrawCircle(x, y, radius);
  95.     }
  96. };
  97. // 绘制椭圆的命令
  98. class DrawEllipseCommand : public Command {
  99. private:
  100.     Receiver* receiver;
  101.     int x, y, majorAxis, minorAxis;
  102. public:
  103.     DrawEllipseCommand(Receiver* r, int x, int y, int majorAxis, int minorAxis)
  104.         : receiver(r), x(x), y(y), majorAxis(majorAxis), minorAxis(minorAxis) {}
  105.     void execute() override {
  106.         receiver->drawEllipse(x, y, majorAxis, minorAxis);
  107.     }
  108.     void undo() override {
  109.         receiver->undoDrawEllipse(x, y, majorAxis, minorAxis);
  110.     }
  111. };
  112. // 绘制多段线的命令
  113. class DrawPolylineCommand : public Command {
  114. private:
  115.     Receiver* receiver;
  116.     std::vector<std::pair<int, int>> points;
  117. public:
  118.     DrawPolylineCommand(Receiver* r, const std::vector<std::pair<int, int>>& points)
  119.         : receiver(r), points(points) {}
  120.     void execute() override {
  121.         receiver->drawPolyline(points);
  122.     }
  123.     void undo() override {
  124.         receiver->undoDrawPolyline(points);
  125.     }
  126. };
  127. // 调用者:工具栏或按钮
  128. class Invoker {
  129. private:
  130.     std::stack<std::shared_ptr<Command>> commandHistory;  // 历史命令栈
  131.     std::stack<std::shared_ptr<Command>> redoStack;      // 重做命令栈
  132. public:
  133.     void executeCommand(std::shared_ptr<Command> cmd) {
  134.         cmd->execute();
  135.         commandHistory.push(cmd);  // 将命令压入历史栈
  136.         while (!redoStack.empty()) {  // 清空重做栈
  137.             redoStack.pop();
  138.         }
  139.     }
  140.     void undo() {
  141.         if (!commandHistory.empty()) {
  142.             std::shared_ptr<Command> cmd = commandHistory.top();
  143.             commandHistory.pop();
  144.             cmd->undo();
  145.             redoStack.push(cmd);  // 将撤销的命令压入重做栈
  146.         } else {
  147.             std::cout << "No command to undo.\n";
  148.         }
  149.     }
  150.     void redo() {
  151.         if (!redoStack.empty()) {
  152.             std::shared_ptr<Command> cmd = redoStack.top();
  153.             redoStack.pop();
  154.             cmd->execute();
  155.             commandHistory.push(cmd);  // 将重做的命令压入历史栈
  156.         } else {
  157.             std::cout << "No command to redo.\n";
  158.         }
  159.     }
  160. };
  161. // 客户端代码
  162. int main() {
  163.     Receiver receiver;  // 绘图工具(画布)
  164.     // 创建具体的命令
  165.     std::shared_ptr<Command> drawPoint = std::make_shared<DrawPointCommand>(&receiver, 10, 20);
  166.     std::shared_ptr<Command> drawLine = std::make_shared<DrawLineCommand>(&receiver, 10, 20, 30, 40);
  167.     std::shared_ptr<Command> drawCircle = std::make_shared<DrawCircleCommand>(&receiver, 50, 50, 15);
  168.     std::shared_ptr<Command> drawEllipse = std::make_shared<DrawEllipseCommand>(&receiver, 70, 70, 20, 10);
  169.     std::vector<std::pair<int, int>> polylinePoints = {{10, 10}, {20, 20}, {30, 30}, {40, 40}};
  170.     std::shared_ptr<Command> drawPolyline = std::make_shared<DrawPolylineCommand>(&receiver, polylinePoints);
  171.     // 创建调用者
  172.     Invoker invoker;
  173.     // 模拟用户操作,通过调用命令绘制图形
  174.     invoker.executeCommand(drawPoint);
  175.     invoker.executeCommand(drawLine);
  176.     invoker.executeCommand(drawCircle);
  177.     invoker.executeCommand(drawEllipse);
  178.     invoker.executeCommand(drawPolyline);
  179.     // 撤销操作
  180.     std::cout << "\nUndoing the last command:\n";
  181.     invoker.undo();
  182.     // 回退(重
  183. 做)操作
  184.     std::cout << "\nRedoing the last undone command:\n";
  185.     invoker.redo();
  186.     return 0;
  187. }
复制代码
关键修改:


  • Command接口:添加了undo()方法,使每个命令都能打消其操纵。
  • Receiver类:为每个绘制方法添加了打消方法(undoDraw...),用于打消详细的图形操纵。
  • Invoker类:管理两个栈——commandHistory(历史命令栈)和redoStack(重做命令栈)。在实行命令时将其压入commandHistory,在打消时将命令从commandHistory中取出并实行undo(),同时将命令压入redoStack。回退时从redoStack取出命令并重新实行。
输出:

  1. Drawing point at (10, 20).
  2. Drawing line from (10, 20) to (30, 40).
  3. Drawing circle at (50, 50) with radius 15.
  4. Drawing ellipse at (70, 70) with major axis 20 and minor axis 10.
  5. Drawing polyline with the following points:
  6. (10, 10) (20, 20) (30, 30) (40, 40)
  7. Undoing the last command:
  8. Undo drawing polyline with the following points:
  9. (10, 10) (20, 20) (30, 30) (40, 40)
  10. Redoing the last undone command:
  11. Drawing polyline with the following points:
  12. (10, 10) (20, 20) (30, 30) (40, 40)
复制代码
功能扩展:



  • 打消操纵:允许打消最后的绘图命令。
  • 回退操纵:允许重做之前打消的命令。
这样,我们就实现了打消和回退功能,用户可以随时打消之前的操纵并规复它们。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表