Do/Undo using command pattern in Python

旧时模样 提交于 2019-12-01 13:23:50

Here is an implementation keeping the commands in a list.

# 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)

How I'd go about this

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)

Some thoughts:

  1. Trying to undo an action can be hard. For example, how would you undraw a line? You'd need to recover what used to be under that line. A simpler approach is often to revert to a clean slate and then reapply all the commands.
  2. Each command should be contained in a single object. It should store all of the data neccesary for the command.
  3. In python you don't need to define the Command class. I do it to provide documentation for what methods I expect Command objects to implement.
  4. You may eventually get speed issues reapplying all the command for an undo. Optimization is left as an excersize for the reader.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!