在Python中使用命令模式执行/撤消

时间:2011-09-22 03:07:44

标签: python design-patterns command

我已经读过使用命令模式是实现执行/撤消功能的最常用方法之一。实际上,我已经看到可以堆叠一堆动作并反转它们以达到给定状态。但是,我不太确定如何在Python中完成这些工作以及我阅读的大部分教程,涉及到概念,但没有在Python中显示实际的实现。

有谁知道在Python中如何/撤消功能?

作为参考,这是我的(天真的,可能是错误的)错误代码:

# command
class DrawCommand:
    def __init__(self, draw, point1, point2):
        self.draw = draw
        self.point1 = point1
        self.point2 = point2
    def execute_drawing(self):
        self.draw.execute(self.point1, self.point2)
    def execute_undrawing(self):
        self.draw.unexecute(self.point1, self.point2)
# invoker
class InvokeDrawALine:
    def command(self, command):
        self.command = command
    def click_to_draw(self):
        self.command.execute_drawing()
    def undo(self):
        self.command.execute_undrawing()
# receiver
class DrawALine:
    def execute(self, point1, point2):
        print("Draw a line from {} to {}".format(point1, point2))
    def unexecute(self, point1, point2):
        print("Erase a line from {} to {}".format(point1, point2))

实例化如下:

invoke_draw = InvokeDrawALine()
draw_a_line = DrawALine()
draw_command = DrawCommand(draw_a_line, 1, 2)
invoke_draw.command(draw_command)
invoke_draw.click_to_draw()
invoke_draw.undo()

输出:

Draw a line from 1 to 2
Erase a line from 1 to 2

显然,此测试不允许堆栈多个操作撤消。也许我完全错了所以我会感激一些帮助。

2 个答案:

答案 0 :(得分:2)

我如何解决这个问题

class Command(object):
    def execute(self, canvas):
         raise NotImplementedError

class DrawLineCommand(Command):
    def __init__(self, point1, point2):
        self._point1 = point1
        self._point2 = point2

    def execute(self, canvas):
        canvas.draw_line(self._point1, self._point2)

 class DrawCircleCommand(Command):
     def __init__(self, point, radius):
        self._point = point
        self._radius = radius

     def execute(self, canvas):
        canvas.draw_circle(self._point, self._radius)

class UndoHistory(object):
    def __init__(self, canvas):
        self._commands = []
        self.canvas = canvas

    def command(self, command):
        self._commands.append(command)
        command.execute(self.canvas)

    def undo(self):
        self._commands.pop() # throw away last command
        self.canvas.clear()
        for command self._commands:
            command.execute(self.canvas)

一些想法:

  1. 尝试撤消操作可能很难。例如,你会如何画一条线?你需要恢复那条线以下的东西。一种更简单的方法通常是恢复到干净的平板,然后重新应用所有命令。
  2. 每个命令都应包含在一个对象中。它应该存储命令所需的所有数据。
  3. 在python中,您不需要定义Command类。我这样做是为了提供我期望Command对象实现的方法的文档。
  4. 您最终可能会遇到速度问题,重新应用撤消的所有命令。优化留给读者作为一个例外。

答案 1 :(得分:2)

这是一个将命令保存在列表中的实现。

# command
class DrawCommand:
    def __init__(self, draw, point1, point2):
        self.draw = draw
        self.point1 = point1
        self.point2 = point2
    def execute_drawing(self):
        self.draw.execute(self.point1, self.point2)
# invoker
class InvokeDrawLines:
    def __init__(self, data):
        self.commandlist = data
    def addcommand(self, command):
        self.commandlist.append(command)
    def draw(self):
        for cmd in self.commandlist:
            cmd.execute_drawing()
    def undocommand(self, command):
        self.commandlist.remove(command)

# receiver
class DrawALine:
    def execute(self, point1, point2):
        print("Draw a line from" , point1, point2)