Padrão de Projeto Command: Encapsulamento de Requisições e Ações

Introdução ao Padrão Command

O padrão Command é um padrão de projeto comportamental que transforma uma solicitação em um objeto independente contendo todas as informações sobre a ação. Essa transformação permite parametrizar métodos com diferentes solicitações, atrasar ou colocar a execução de uma requisição em fila, e suportar operações desfazíveis.

O principal objetivo é desacoplar o objeto que invoca a operação daquele que sabe como realizá-la, permitindo que a comunicação ocorra exclusivamente através do objeto de comando.

Componentes Principais

  • Invocador (Invoker): O objeto responsável por iniciar a requisição. Ele mantém uma referência ao objeto de comando e aciona sua execução.
  • Comando (Command): Uma interface que declara o método para a execução da ação.
  • Comando Concreto (Concrete Command): Implementa a interface de comando e define a ligação entre o objeto receptor e a ação a ser executada.
  • Receptor (Receiver): Contém a lógica de negócio real. É o objeto que executa a ação quando o comando é acionado.
  • Cliente (Client): Cria e configura os objetos de comando concretos, associando-os aos seus respectivos receptores e invocadores.

Cenários de Aplicação

  • Desacoplamento de Camadas: Separar a interface do usuário (como botões ou menus) da lógica de negócio subjacente.
  • Histórico de Operações (Undo/Redo): Implementar funcionalidades de desfazer e refazer em editores de texto ou softwarse de design.
  • Agendamento e Filas: Armzaenar comandos em uma fila para execução assíncrona ou agendada.
  • Gerenciamento de Transações: Agrupar múltiplas operações em uma transação atômica, permitindo rollback em caso de falha.
  • Macros: Executar uma sequência de comandos como uma única operação combinada.

Vantagens

  • Princípio da Responsabilidade Única: Isola a lógica de execução em classes separadas, facilitando a manutenção.
  • Princípio Aberto/Fechado: Novos comandos podem ser introduzidos sem a necessidade de alterar o código existente.
  • Controle de Execução: Permite implementar operações de desfazer, refazer e agendamento de forma natural e estruturada.

Desvantagens

  • Explosão de Classes: A criação de um novo comando para cada ação pode resultar em um grande número de classes e interfaces no projeto.
  • Complexidade Adicional: Para operações triviais e simples, o padrão pode introduzir uma sobrecarga de design desnecessária.

Exemplo de Implementação

Abaixo, apresentamos uma implementação utilizando um cenário de controle de um Drone, onde um painel de controle (Invocador) aciona ações de decolagem e pouso (Comandos) que são efetivamente executadas pelo próprio Drone (Receptor).

Go

package command

import "fmt"

// Action define a interface para o comando
type Action interface {
	Run()
}

// FlightController atua como o invocador
type FlightController struct {
	action Action
}

func (fc *FlightController) Trigger() {
	fc.action.Run()
}

// TakeOffAction é um comando concreto
type TakeOffAction struct {
	machine Drone
}

func (t *TakeOffAction) Run() {
	t.machine.Ascend()
}

// LandAction é outro comando concreto
type LandAction struct {
	machine Drone
}

func (l *LandAction) Run() {
	l.machine.Descend()
}

// Drone é o receptor
type Drone struct {
	isFlying bool
}

func (d *Drone) Ascend() {
	d.isFlying = true
	fmt.Println("Drone decolando...")
}

func (d *Drone) Descend() {
	d.isFlying = false
	fmt.Println("Drone pousando...")
}

Teste do Cliente:

package command

import "testing"

func TestDroneCommand(t *testing.T) {
	myDrone := &Drone{}

	takeOff := &TakeOffAction{
		machine: myDrone,
	}

	land := &LandAction{
		machine: myDrone,
	}

	controller := &FlightController{
		action: takeOff,
	}
	controller.Trigger()

	controller.action = land
	controller.Trigger()
}

Python

from abc import ABC, abstractmethod

class Action(ABC):
    @abstractmethod
    def run(self):
        pass

class Machine(ABC):
    @abstractmethod
    def ascend(self):
        pass

    @abstractmethod
    def descend(self):
        pass

class FlightController:
    def __init__(self, action: Action):
        self.action = action

    def trigger(self):
        self.action.run()

class TakeOffAction(Action):
    def __init__(self, machine: Machine):
        self.machine = machine

    def run(self):
        self.machine.ascend()

class LandAction(Action):
    def __init__(self, machine: Machine):
        self.machine = machine

    def run(self):
        self.machine.descend()

class Drone(Machine):
    def __init__(self):
        self.is_flying = False

    def ascend(self):
        self.is_flying = True
        print("Drone decolando...")

    def descend(self):
        self.is_flying = False
        print("Drone pousando...")

if __name__ == "__main__":
    drone = Drone()

    take_off_cmd = TakeOffAction(drone)
    land_cmd = LandAction(drone)

    panel = FlightController(take_off_cmd)
    panel.trigger()

    panel.action = land_cmd
    panel.trigger()

Tags: Padrão de Projeto Command padrões comportamentais design patterns go Python

Publicado em 6-15 01:34 por Thomas