Padrão Command
Parte da seção Object Oriented Programming do Journey de Python da Coddy — lição 49 de 64.
O padrão Command encapsula uma solicitação como um objeto, permitindo que você enfileire operações, registre solicitações e suporte a funcionalidade de desfazer. Ele separa o objeto que chama a operação daquele que a executa.
Aqui estão algumas classes de comando simples:
class Command:
def execute(self):
pass
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()Cada comando encapsula uma operação específica em um objeto receptor.
Crie o receptor que realiza o trabalho real:
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")Crie um invoker que executa comandos:
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()Use o padrão command:
# Criar receptor
light = Light()
# Criar comandos
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)
# Criar invocador
remote = RemoteControl()
# Executar comandos diferentes
remote.set_command(light_on)
remote.press_button()
remote.set_command(light_off)
remote.press_button()Adicione suporte para operações de desfazer:
class UndoableCommand(Command):
def undo(self):
pass
class LightOnCommand(UndoableCommand):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
def undo(self):
self.light.turn_off()
class SmartRemote:
def __init__(self):
self.last_command = None
def execute_command(self, command):
command.execute()
self.last_command = command
def undo(self):
if self.last_command:
self.last_command.undo()
smart_remote = SmartRemote()
smart_remote.execute_command(LightOnCommand(light))
smart_remote.undo() # Desliga a luzSaída:
Light is on
Light is off
Light is on
Light is offPonto Chave: O Command Pattern transforma solicitações em objetos que podem ser armazenados, passados e executados posteriormente. O invoker não precisa saber como realizar a operação - ele apenas chama execute() no objeto de comando. Isso possibilita recursos como desfazer/refazer (undo/redo), enfileiramento de operações e log de comandos.
Desafio
FácilNeste desafio, você implementará a classe base fundamental Command em command.py — o bloco de construção essencial do Command Pattern. Este exercício foca especificamente em encapsulamento: armazenar dados de forma privada e expô-los com segurança através de uma propriedade.
Modifique apenas o arquivo command.py de acordo com os comentários TODO. Os comentários TODO guiarão você para:
- Armazenar o nome do comando como um atributo privado (
_name) - Expô-lo via uma propriedade somente leitura (
name) - Implementar um método
display_info()que imprime o nome do comando
Nota: Este desafio cobre apenas a classe base Command — o Invoker, Receiver e a funcionalidade de desfazer (undo) são introduzidos em lições posteriores. Concluir esta etapa fornece a base de encapsulamento sobre a qual o padrão completo é construído.
Sua implementação será testada pelo driver.py, que valida:
- Funcionalidade básica e formato de saída
- Casos de borda (entradas vazias, caracteres especiais, nomes longos)
- Proteção de propriedade somente leitura (tentar
obj.name = ...deve gerar umAttributeError) - Presença do atributo privado
_name
Folha de consulta
O Command Pattern (Padrão de Comando) encapsula uma solicitação como um objeto, permitindo que você enfileire operações, registre solicitações e suporte a funcionalidade de desfazer.
Estrutura básica de comando:
class Command:
def execute(self):
pass
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()Crie um receptor (receiver) que realize o trabalho real:
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")Crie um invocador (invoker) que execute comandos:
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()Exemplo de uso:
# Criar receptor
light = Light()
# Criar comandos
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)
# Criar invocador
remote = RemoteControl()
# Executar comandos diferentes
remote.set_command(light_on)
remote.press_button()
remote.set_command(light_off)
remote.press_button()Adicionar funcionalidade de desfazer:
class UndoableCommand(Command):
def undo(self):
pass
class LightOnCommand(UndoableCommand):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
def undo(self):
self.light.turn_off()
class SmartRemote:
def __init__(self):
self.last_command = None
def execute_command(self, command):
command.execute()
self.last_command = command
def undo(self):
if self.last_command:
self.last_command.undo()Experimente você mesmo
# Importa a classe Command do arquivo command.py
from command import Command
# Manipulador abrangente de casos de teste
test_case = input()
if test_case == "basic_test":
obj = Command("Test Name")
obj.display_info()
elif test_case == "validation_test":
obj = Command("Validation Test")
print(f"Name: {obj.name}")
elif test_case == "empty_name_test":
obj = Command("")
obj.display_info()
print(f"Empty name handled: {'Yes' if obj.name == '' else 'No'}")
elif test_case == "property_access_test":
obj = Command("Property Test")
original_name = obj.name
try:
# Isso deve falhar, pois name é uma propriedade somente leitura
obj.name = "Modified Name"
print("Property protection failed")
except AttributeError:
print("Property protected successfully")
print(f"Name unchanged: {obj.name == original_name}")
elif test_case == "multiple_commands_test":
commands = [
Command("First Command"),
Command("Second Command"),
Command("Third Command")
]
for cmd in commands:
cmd.display_info()
elif test_case == "attribute_test":
obj = Command("Attribute Test")
has_private_name = hasattr(obj, "_name")
print(f"Has _name attribute: {has_private_name}")
elif test_case == "special_chars_test":
obj = Command("!@#$%^&*()_+{}[]|\\:;\"'<>,.?/")
obj.display_info()
elif test_case == "long_name_test":
long_name = "A" * 100
obj = Command(long_name)
obj.display_info()
print(f"Name length: {len(obj.name)}")Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosO Parâmetro selfMétodosAtributosMétodo Construtor (__init__)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Função super()Sobrescrita de MétodoHerança MúltiplaOrdem de Resolução de MétodosRecapitulação - Hierarquia de Funcionários7Métodos Especiais
Introdução aos Métodos MágicosSobrecarga de OperadoresMétodos Mágicos de ContêinerRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução a Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy2Decoradores
Introdução aos DecoradoresDecorador de PropriedadeDecorador de Método EstáticoDecorador de Método de Classe5Polimorfismo
Sobrescrita de Método RevisitadaDuck TypingClasses e Métodos AbstratosDesign de InterfacesRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição vs HerançaMixinsMétodos Estáticos e de ClasseDecoradores de ClasseGerenciadores de Contexto11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Propriedades de Classe
Variáveis de Instância vs de ClasseDecoradores de PropriedadeAtributos PrivadosRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Membros Públicos, Protegidos e PrivadosModificadores de AcessoOcultação de InformaçãoProperty Decorators AvançadosRecapitulação - Sistema de Registro de Alunos12Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário