Entendendo o padrão de projeto Command em Java
Com o padrão de projeto Command, você pode encapsular uma solicitação como um objeto, permitindo que você parametrize clientes com diferentes solicitações, enfileire ou registre solicitações e suporte operações que podem ser desfeitas.
Imagine que você esteja desenvolvendo uma aplicação de edição de texto e queira permitir que o usuário desfaça e refaça suas ações. O padrão de projeto Command pode ser usado para implementar essa funcionalidade.
A ideia básica é encapsular cada ação do usuário como um objeto Command, que armazena informações sobre a ação e fornece um método para executá-la e outro para desfazê-la. Esses objetos Command são então enfileirados ou registrados em um objeto invocador, que é responsável por executá-los e desfazê-los.
Exemplo de implementação em Java
Veja um exemplo de código em Java para entender melhor como funciona o padrão de projeto Command:
// Interface que define o método execute() que deve ser implementado por todos os comandos
public interface Command {
void execute();
void undo();
}
// Implementação concreta de um comando que adiciona um caractere ao texto
public class AddCharCommand implements Command {
private final char character;
private final TextEditor textEditor;
public AddCharCommand(char character, TextEditor textEditor) {
this.character = character;
this.textEditor = textEditor;
}
public void execute() {
textEditor.addChar(character);
}
public void undo() {
textEditor.deleteChar();
}
}
// Implementação concreta de um comando que remove um caractere do texto
public class DeleteCharCommand implements Command {
private final TextEditor textEditor;
private char lastDeletedChar;
public DeleteCharCommand(TextEditor textEditor) {
this.textEditor = textEditor;
}
public void execute() {
lastDeletedChar = textEditor.deleteChar();
}
public void undo() {
textEditor.addChar(lastDeletedChar);
}
}
// Classe invocadora que mantém uma lista de comandos executados e permite desfazê-los
public class CommandInvoker {
private final List<Command> executedCommands = new ArrayList<>();
public void executeCommand(Command command) {
command.execute();
executedCommands.add(command);
}
public void undoLastCommand() {
if (!executedCommands.isEmpty()) {
Command lastCommand = executedCommands.remove(executedCommands.size() - 1);
lastCommand.undo();
}
}
}
// Classe que representa o editor de texto
public class TextEditor {
private final StringBuilder text = new StringBuilder();
public void addChar(char c) {
text.append(c);
}
public char deleteChar() {
int lastIndex = text.length() - 1;
char lastChar = text.charAt(lastIndex);
text.deleteCharAt(lastIndex);
return lastChar;
}
public String getText() {
return text.toString();
}
}
// Exemplo de uso do padrão de projeto Command
public class Application {
public static void main(String[] args) {
TextEditor textEditor = new TextEditor();
CommandInvoker commandInvoker = new CommandInvoker();
commandInvoker.executeCommand(new AddCharCommand('b', textEditor));
commandInvoker.executeCommand(new AddCharCommand('l', textEditor));
commandInvoker.executeCommand(new AddCharCommand('o', textEditor));
commandInvoker.executeCommand(new AddCharCommand('g', textEditor));
// exibe blog
System.out.println(textEditor.getText());
commandInvoker.executeCommand(new DeleteCharCommand(textEditor));
commandInvoker.executeCommand(new DeleteCharCommand(textEditor));
// exibe bl
System.out.println(textEditor.getText());
commandInvoker.undoLastCommand();
commandInvoker.undoLastCommand();
// exibe blog
System.out.println(textEditor.getText());
}
}
Agora que já vimos o exemplo de implementação do padrão de projeto Command em Java, vamos entender um pouco mais sobre suas vantagens e desvantagens.
Vantagens
-
Separação de responsabilidades: O padrão Command ajuda a separar a lógica do comando da classe que o invoca, reduzindo o acoplamento entre as classes e melhorando a coesão do código.
-
Suporte a desfazer e refazer ações: O padrão Command permite que as ações executadas sejam desfeitas ou refeitas facilmente, já que as informações necessárias para isso são armazenadas nos objetos de comando.
-
Flexibilidade: Como os comandos são objetos, é possível criar novos comandos e adicioná-los ao sistema sem afetar as classes que já existem.
Desvantagens
-
Aumento da complexidade: O padrão Command pode aumentar a complexidade do código, pois exige a criação de muitas classes adicionais para cada comando.
-
Custo em termos de memória: Como os objetos de comando mantêm informações sobre as ações que executam, eles podem consumir mais memória do que uma simples chamada de método.
-
Dificuldade em lidar com comandos assíncronos: O padrão Command é mais adequado para lidar com comandos síncronos, pois não fornece um mecanismo padrão para lidar com comandos assíncronos.
Conclusão
O padrão de projeto Command é uma ótima opção quando se trata de lidar com ações complexas em um sistema. Ele ajuda a separar a lógica do comando da classe que o invoca, permitindo maior flexibilidade e suporte a desfazer e refazer ações. Por outro lado, pode aumentar a complexidade do código e consumir mais memória. No geral, é uma escolha sólida para aplicações que exigem manipulação de comandos complexos.