Почитать описание других паттернов.

Необходимо иметь эффективное представление запросов к некоторой системе, не обладая при этом знаниями ни об их природе ни о способах их обработки.
Существует по крайней мере три мотивации к использованию шаблона “Команда”:

Проблема
Необходимо иметь эффективное представление запросов к некоторой системе, не обладая при этом знаниями ни об их природе ни о способах их обработки.
Описание
Существует по крайней мере три мотивации к использованию шаблона “Команда”:
- инкапсулирование запроса в виде объекта для последующего протоколирования/логирования и т.п.
- наделение сущности “вызов метода объекта” свойствами самостоятельного объекта;
- объектно-ориентированный обратный вызов (callback);
На самом деле все вышеперечисленные мотивации сводятся к одной — “инкапсулирование запроса в виде объекта”. Известно большое количество типов систем, где подобный подход эффективен и оправдан. Во первых — это любое более мене серьезное desktop-приложение c возможностями отмены и повторения действий пользователя (undo/redo). Во вторых, это сетевые распределенные системы использующие запросы в виде объектов в качестве основного примитива инициализации каких-либо операций. В третьих — системы с поддержкой асинхронных вызовов, инкапсулирующие обратный вызов в виде callback-объекта. Перечислять можно бесконечно, важно понять, что шаблон команда — один из самых распространенных шаблонов, который, можно сказать, появился буквально на этапе становления ООП и только потом был формализован и описан в книге GoF.
Основополагающая идея шаблона заключается в использовании единого интерфейса для описания всех типов операций, которые можно производить с системой. Тогда для добавления в систему поддержки новой операции достаточно реализовать предлагаемый интерфейс. Таким образом, каждая операция представляется самостоятельным объектом инкапсулирующим некоторый набор дополнительных свойств. Систем, в свою очередь, приобретает возможно выполнять дополнительный набор действий над запросами (объектами). Это протоколирование, отмена предыдущего действия повторение последующего и т.д.
Практический пример
Рассмотрим самую очевидную мотивацию для использования шаблона — логирование/undo-redo. Для этого, представим чтобы было,<sarcasm>
если бы Стивен Борн (автор bash) прочитал книгу GoF и знал что такое паттерн проектирования “Команда”</sarcasm>
. Было бы примерно следующие:
- каждая команда в оболочке инкаспулировалась бы в отдельный класс — потомок класса Command;
- командная оболочка поддерживала бы механизмы протоколирования/логирования и что самое главное — отмены и повторения (undo/redo) действий пользователя, т.е. команд;
Попытаемся изменить проблемы в дизайне существующих решений и напишем свойвелосипедшел с возможностью отмены и повторения команд.
Для достижения поставленной цели достаточно ввести понятие очереди выполненных команд, куда попадает всякая команда (объект, наследник Command) после выполнения и очереди отмененных команд, куда поступает любая отмененная команда. Помимо этого, необходимо иметь разделенные механизмы выполнения и отмены действий команды. Очевидно, что эти механизмы индивидуальны для каждой команды. Тогда для реализации целостной системы нам достаточно, оперируя двумя очередями применять к объектам находящимся в их верхушке соответствующие действия — выполнение или отмену.
Диаграмма классов
Каждая команда, поддерживаемая оболочкой должна расширять класс Command, реализуя при этом три метода — execute(), cancel() и name() — выполнение, отмена и имя команды соответственно.
Класс командной оболочки изображен лишь для наглядности. В приведенной реализации его заменяет метод main().
Реализация на Python
# -*- coding: cp1251 -*- from sys import stdout as console # Обработка команды exit class SessionClosed(Exception): def __init__(self, value): self.value = value # Интерфейс команды class Command: def execute(self): raise NotImplementedError() def cancel(self): raise NotImplementedError() def name(): raise NotImplementedError() # Команда rm class RmCommand(Command): def execute(self): console.write("You are executed \"rm\" command\n") def cancel(self): console.write("You are canceled \"rm\" command\n") def name(self): return "rm" # Команда uptime class UptimeCommand(Command): def execute(self): console.write("You are executed \"uptime\" command\n") def cancel(self): console.write("You are canceled \"uptime\" command\n") def name(self): return "uptime" # Команда undo class UndoCommand(Command): def execute(self): try: cmd = HISTORY.pop() TRASH.append(cmd) console.write("Undo command \"{0}\"\n".format(cmd.name())) cmd.cancel() except IndexError: console.write("ERROR: HISTORY is empty\n") def name(self): return "undo" # Команда redo class RedoCommand(Command): def execute(self): try: cmd = TRASH.pop() HISTORY.append(cmd) console.write("Redo command \"{0}\"\n".format(cmd.name())) cmd.execute() except IndexError: console.write("ERROR: TRASH is empty\n") def name(self): return "redo" # Команда history class HistoryCommand(Command): def execute(self): i = 0 for cmd in HISTORY: console.write("{0}: {1}\n".format(i, cmd.name())) i = i + 1 def name(self): print "history" # Команда exit class ExitCommand(Command): def execute(self): raise SessionClosed("Good bay!") def name(self): return "exit" # Словарь доступных команд COMMANDS = {'rm': RmCommand(), 'uptime': UptimeCommand(), 'undo': UndoCommand(), 'redo': RedoCommand(), 'history': HistoryCommand(), 'exit': ExitCommand()} HISTORY = list() TRASH = list() # Шелл def main(): try: while True: console.flush() console.write("pysh >> ") cmd = raw_input() try: command = COMMANDS[cmd] command.execute() if not isinstance(command, UndoCommand) and not isinstance(command, RedoCommand) and not isinstance(command, HistoryCommand): TRASH = list() HISTORY.append(command) except KeyError: console.write("ERROR: Command \"%s\" not found\n" % cmd) except SessionClosed as e: console.write(e.value) if __name__ == "__main__": main()
Использование
$ python pysh.py pysh >> rm You are executed "rm" command pysh >> rm You are executed "rm" command pysh >> rm You are executed "rm" command pysh >> history 0: rm 1: rm 2: rm pysh >> undo Undo command "rm" You are canceled "rm" command pysh >> exit Good bay!
Примечание
В некоторых источниках шаблон называется Действие/Action или Транзакция/Transaction.