Entendendo os padrões de projeto a partir da análise de frameworks populares de mercado: Padrões comportamentais

Behavioral design patterns

Dando prosseguimento ao estudo sobre a aplicação de padrões de projeto em ferramentas de mercado, falamos anteriormente sobre alguns casos de uso que tratam a instanciação de novos objetos a partir da aplicação de padrões de projeto criacionais como é o caso do StringBuilder, falamos também sobre alguns cenários nos quais abstrações de padrões de projeto estruturais determinaram estruturas como o FilterInputStream. Neste artigo, tenho a intenção de expor aplicações de padrões de projeto comportamentais.

Como é de praxe, começaremos com uma breve introdução ao que são os padrões de projeto comportamentais. Em resumo, as abstrações enumeradas por Gamma et al. e que possuem como principal caracteristica a preocupação com a forma pela qual objetos satisfazem a comunicação entre dois ou mais são classificadas como padrões comportamentais. Em geral classes que pertencem a esse grupo tendem a descrever padrões comuns de comunicação entre entidades enaltecendo maneiras flexíveis de carregar essa propriedade e por isso nos auxiliam, mais uma vez, a desenvolver sistemas de baixo acoplamento. Veremos agora aplicações dos onze modelos mais conhecidos desse grupo: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method e Visitor.

  1. Chain of responsibility é um padrão que permite mais de um objeto tratar uma solicitação a partir de um encadeamento. A partir do uso dele, é menor o acoplamento entre o remetente e o destinatário de uma ação. Um exemplo do uso desse padrão seria o encadeamento de filtros no Java (javax.servlet.Fiter.doFilter()). Outro exemplo é o tratamento de exceções, no qual uma exceção recursivamente escala a pilha de métodos até encontrar um capaz de tratá-la.

  2. Command (também conhecido como Action ou Transaction) pode ser traduzido como uma forma de encapsular uma ação como um objeto. Com isso ele torna simples a execução encadeada de comandos, a forma com que diferentes ações dentro de um sistema são chamadas, além de dar suporte a operações que possam ser desfeitas. Alguns exemplos encontrados em Java seriam as implementações de javax.swing.Action.

  3. Interpreter é um modelo que auxilia a interpretação de sentenças de uma linguagem partindo de uma representação gramatical e, justamente por essa razão, ele pode ser encontrado na implementação em alguns compiladores. Um exemplo de uso desse padrão em Java seria a classe java.util.Pattern.

  4. Iterator é um padrão muito utilizado em loops como, por exemplo, o for-each, proveniente do Java. Trata-se de uma maneira para se acessar sequencialmente os elementos de um conjunto de objetos sem a necessidade de conhecimento dos elementos subsequentes. Todas as implementações de java.util.Iterator fazem uso dele.

  5. Mediator atua como uma solução que encapsula a forma de comunicação entre um conjunto de objetos. Ele é interessante porque evita que um objeto se refira explicitamente a outro, e isso permite que as interações entre eles sejam variadas independentemente. Por exemplo, a interface PanelMediator, do pacote java.awt.event.ActionListener, é útil para implementar uma janela com vários componentes que interagem entre si. Ela centraliza a comunicação no Mediador que é responsável por despachá-las aos componentes certos e desse modo faz com que não precisem se comunicar diretamente.

  6. Memento é um padrão comportamental que modela uma maneira de se capturar o estado interno de um objeto, permitindo a possibilidade de restaurá-lo posteriormente. Nesse sentido, uma classe bem conhecida é a java.util.Date, que faz uso de um tipo long interno para guardar o valor da data, mas que é acessado por métodos que entendem Date.

  7. Observer resolve a dificuldade que existe quando um objeto muda de estado e necessita notificar vários outros. Nesse padrão, quando o objeto pai é modificado, todos os seus dependentes são automaticamente notificados e atualizados. Geralmente estes padrões são encontrados como implementações de Java.util.EventListener.

  8. State é um padrão que permite um objeto alterar seu comportamento quando o seu estado interno mudar. Outra forma de entendê-lo seria imaginando que no momento da mudança do estado do objeto, é como se ele transformasse numa instância de uma classe completamente diferente. Por exemplo, o comportamento de javax.faces.Lyfecycle que é dependente do estado do ciclo de vida do JSF.

  9. Strategy é outro padrão bastante conhecido que torna possível a mudança comportamental de um objeto a partir do encapsulamento de algoritmos. Um exemplo de aplicação seria na ordenação de listas, onde uma comparação, como o compare(), do pacote Java.util.Comparator, decide qual é elemento de maior valor dentro de subconjuntos numéricos, alfabéticos ou outros.

  10. Template Method está relacionado com a possibilidade de se criar o esqueleto de um algoritmo realizando uma operação de forma a postergar alguns passos para as subclasses que o implementa. Em outras palavras, são as subclasses dele que redefinem alguns passos da operação, sem a necessidade de mudança na estrutura. Os métodos não abstratos de java.util.AbstractList usam esse padrão. Eles são rotinas pré-produzidas que fazem o uso de métodos abstratos implementados nas subclasses delas.

  11. Visitor é um padrão que representa uma operação que é executada sobre os elementos de uma estrutura de um objeto, ou seja, sobre objetos que constituem o objeto original. Com aaplicação dele é possível acessar cada parte do objeto pai, sem modificar as classes dos elementos filho. Um exemplo seria o ElementVisitor do pacote javax.lang.model.element que opera em conjunto com o objeto Element do mesmo pacote.

E assim terminamos nossa análise sobre aplicações de padrões de projeto em frameworks de mercado. Espero que tenham gostado e até a próxima…

Anúncios