Padrões de design: comando – Agatetepê
Carlos Caballero em HackerNoon.com Seguir Mai 23 · 7 min ler
Existem 23 padrões de design clássico, descritos no livro original, Design Patterns: Elements of Reusable Object-Oriented Software . Esses padrões fornecem soluções para problemas específicos, frequentemente repetidos no desenvolvimento de software.
Neste artigo, vou descrever como o padrão de comando; e como e quando deve ser aplicado.
Padrão de Comando: Idéia Básica
Na programação orientada a objetos, o padrão de comando é um padrão de design comportamental no qual um objeto é usado para encapsular todas as informações necessárias para executar uma ação ou acionar um evento posteriormente. Esta informação inclui o nome do método, o objeto que possui o método e os valores para os parâmetros do método – Wikipedia
Encapsule uma solicitação como um objeto, permitindo assim parametrizar clientes com solicitações diferentes, enfileirar ou registrar solicitações, e dar suporte a operações que podem ser desfeitas – Padrões de design: elementos do software orientado a objeto reutilizável
Nesse padrão, uma classe Command abstrata é declarada como uma interface para executar operações. A classe Command define um método chamado execute , que deve ser implementado em cada comando concreto. Este método de execute é uma ponte entre um objeto Receiver e uma ação. O Receiver sabe como executar as operações associadas a uma solicitação (qualquer classe pode ser um Receiver ). Outro componente relevante neste padrão é a classe Invoker que solicita o comando que deve ser executado.
O diagrama UML para esse padrão é o seguinte:
O padrão de comando deve ser usado quando:
Você precisa de um comando para ter um tempo de vida independente da solicitação original. Além disso, se você deseja enfileirar, especificar e executar solicitações em momentos diferentes.
Você precisa desfazer / refazer as operações. A execução do comando pode ser armazenada para reverter seus efeitos. É importante que a classe Command implemente os métodos desfazer e refazer.
Você precisa estruturar um sistema em torno de operações de alto nível baseadas em operações primitivas.
O padrão de comando tem várias vantagens, resumidas nos seguintes pontos:
Ele separa as classes que invocam a operação do objeto que sabe como executar a operação
Ele permite que você crie uma seqüência de comandos, fornecendo um sistema de fila
Implementar extensões para adicionar um novo comando é fácil e pode ser feito sem alterar o código existente.
Você também pode definir um sistema de reversão com o padrão Command, como no exemplo do Assistente, poderíamos escrever um método de reversão.
Tenha controle rigoroso sobre como e quando os comandos são invocados.
O código é mais fácil de usar, entender e testar, pois os comandos simplificam o código.
Agora vou mostrar como você pode implementar esse padrão usando JavaScript / TypeScript. No nosso caso, stockTrade um problema no qual existe uma classe chamada Agent que define os atributos: stockTrade ; e uma operação placeOrder . Esta classe é a ponte entre o cliente / contexto e o StockTrader . O método placeOrder é responsável por decidir qual ação deve ser executada. Por exemplo, se o orderType for buy ou sell o método deve invocar a ação no StockTrader . O diagrama UML a seguir mostra o cenário que acabei de descrever.
Os códigos do client e do Agent são os seguintes:
O cheiro de código mais relevante é o método placeOrder , que é acoplado às ações / comandos da StockTrade . Existem diferentes técnicas para evitar esse cheiro de código. Nesse caso, o padrão Command é uma boa solução, já que queremos registrar o histórico do comando.
Finalmente, a classe StockTrade é a seguinte:
O resultado obtido é mostrado na imagem a seguir:
Padrão de Comando – Exemplo 1: Um Mercado de Ações – Solução
A ideia de dissociar os comandos da classe Agent é criar um conjunto de classes para cada comando. No entanto, os comandos compartilham uma interface comum que nos permite executar a ação dependendo de cada comando concreto.
Essa é a razão pela qual criamos a classe abstrata Order que terá um método abstrato chamado execute . Este método é aquele que será invocado da classe Agent (o invocador). Além disso, a classe Agent terá uma lista de comandos para obter o histórico do comando.
Desta forma, o agente delega a responsabilidade de saber qual operação deve ser executada no objeto que recebe. A principal mudança é que a classe Agent não receberá mais um atributo primitivo como um parâmetro (string), já que isso não tem valor semântico. Em vez disso, a classe Agent receberá agora um objeto de comando como um parâmetro, que fornece valor semântico.
O novo diagrama UML usando o padrão de comando é mostrado abaixo:
O código associado ao client é o seguinte:
Neste caso, cada order recebe o StockTrade usando DI (Injeção de Dependência). O Agent chama o comando usando o método placeOrder , que executa a operação através do método de execute .
O código associado ao Agent é o seguinte:
Você pode observar que a estrutura de controle if-elseif-else é evitada usando o método order.execute , que delega a responsabilidade a cada comando.
O código associado ao Order e a cada pedido são os seguintes:
A classe StockTrade não é modificada neste comando. Portanto, o resultado após essas modificações na execução do programa é mostrado na imagem a seguir:
Outro exemplo interessante que é resolvido usando o padrão de comando é quando há vários comandos para executar para um robô.
Por exemplo, um conjunto de comandos como
SaveSecret , Clean and Move são pedidos a um robô famoso, o R2D2. No diagrama UML a seguir, você pode ver essa situação:
O código associado aos clientes é o seguinte:
Neste exemplo, existem três comandos (saveSecretCommand, cleanCommand e moveCommand), dois serviços (StoreService e R2D2Service) e um Agente (R2D2).
O Agente invoca as ordens usando o método executeCommand que recebe dois argumentos: 1) O comando; 2) Os parâmetros para executar o comando anterior.
Portanto, o código associado ao R2D2 é o seguinte:
R2D2 tem uma lista de comandos, que podem ser listados através do método listCommands , e armazenados usando a estrutura de dados de commands . Finalmente, o método executeCommand é responsável por invocar o método de execução de cada comando.
Então, o próximo passo é criar o código associado ao comando (classe abstrata) e a cada comando concreto:
Finalmente, cada comando invoca o serviço responsável pela ação, neste caso usamos dois serviços diferentes para mostrar que nem todos os comandos delegam responsabilidade ao mesmo serviço ou classe.
Eu criei um npm scripts que executam o exemplo mostrado aqui depois de aplicar o padrão de comando.
O padrão de comando pode evitar a complexidade em seus projetos porque você encapsula os comandos em classes específicas que podem ser adicionadas / removidas ou alteradas a qualquer momento (incluindo tempo de execução).
O mais importante é não implementar o padrão como mostrei, mas ser capaz de reconhecer o problema que esse padrão específico pode resolver e quando você pode ou não implementar esse padrão. Isso é crucial, pois a implementação irá variar dependendo da linguagem de programação usada.
A ramificação do GitHub deste post é https://github.com/Caballerog/blog/tree/master/command-pattern
Padrões de design: comando e conserje na vida e Ruby
A definição do Padrão de Comando é estressante a ser observada. A definição formal é que: encapsula um pedido como…
Padrões de Design C #: O Padrão de Fábrica
Morgan Kenyon em codeburst Segue 5 de jul · 4 min ler Foto de Ant Rozetsky no Unsplash Padrões de…
Noções Básicas sobre Padrões de Design: Fachada usando Pokemon e Dragonball Exemplos!
Carlos Caballero em HackerNoon.com Seguir Abr 5 · 6 min ler Existem 23 padrões de design clássico, descritos no livro…