Do / Undo, используя шаблон команды в Python - PullRequest
1 голос
/ 22 сентября 2011

Я прочитал, что использование шаблонов команд является одним из самых популярных способов выполнения функций do / undo.На самом деле, я видел, что можно сложить кучу действий и отменить их, чтобы достичь заданного состояния.Тем не менее, я не совсем уверен, как это можно сделать в 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 ]

2 голосов
/ 22 сентября 2011

Вот реализация, хранящая команды в списке.

# 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)
2 голосов
/ 22 сентября 2011

Как бы я поступил об этом

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. В конечном итоге могут возникнуть проблемы со скоростью при повторном применении всей команды для отмены.Оптимизация оставлена ​​как пример для читателя.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...