Exemplo em código dos padrões de projeto
Tags: design, patterns, padroes, projeto
Published: 2022-01-12 14:01:15

Design Patterns (comumente relacionados na literatura de TI como “Padrões de Projeto”) são soluções para problemas comuns que encontramos no desenvolvimento ou manutenção de um software orientado a objetos (não são tão bem aplicáveis em outros paradigmas).

Os padrões GoF foram divididos e categorizados de acordo com a natureza do problema que eles resolvem (ou ao menos tentam, uma vez que software, como bem você sabe, é algo com “vida própria” haha):

Padrões de Criação: Tem como objetivo abstrair a instanciação de objetos. Com eles, o sistema vai solicitar um objeto de um determinado tipo e o terá prontinho, sob demanda, sem nem se preocupar com as nuances da criação. Fazendo um paralelo com o mundo real, uma empresa automobilística quando precisa de amortecedores, ela terceiriza (solicita-os) e então os instala em seus carros, sem se preocupar com o todo envolvido na criação desse componente.

Padrões estruturais: Os padrões dessa categoria se preocupam em melhor organizar a estrutura das classes e os relacionamentos entre classes e objetos.

Padrões comportamentais: Os padrões dessa categoria atuam diretamente na delegação de responsabilidades, definindo como os objetos devem se comportar e se comunicar.

> Texto retirado da Treinaweb

A seguir é possível encontrar os padrões com detalhes e um exemplo de código, divididos por sua aplicação.

**Padrões de Criação**

O Abstract Factory é usado para criarmos diferentes famílias de objetos sem precisar especificar a classe concreta. Assim, definimos uma classe abstrata que cria os recursos e as classes concretas criam as classes de cada família. Este padrão tem relação com os padrões Factory Method, Prototype e Singleton.
[_Abstract Factory_](https://gist.github.com/walteralleyz/2004ec5a8ccc246002ea0a5ae2ef74dc)

O padrão Factory Method utiliza um método de uma classe que cria objetos de outro tipo. Em outras palavras, este padrão fornece uma interface para criar objetos em uma classe mãe e permite que seus filhos alterem o tipo de objeto que será criado.  Os padrões Factories costumam ter vários Factory Methods dentro deles.
[_Factory Method_](https://gist.github.com/walteralleyz/53ec860cba1346f5235267fbb64f8b47)

Este padrão de criação é usado quando temos um “modelo” de um objeto que queremos criar e para criar novos objetos clonamos este objeto. Em uma Factory podemos ter vários Prototypes e a criação de objetos irá gerar cópias deste objeto.
[_Prototype_](https://gist.github.com/walteralleyz/6b32fc7680c1d2f19f1e3f454a6f5b58)

O Singleton é utilizado quando queremos que exista só uma única instância de uma classe e que ela possa ser facilmente acessível de qualquer ponto do programa. É uma boa alternativa às variáveis globais e as classes que só possuem métodos estáticos. Em um Singleton, a própria classe é responsável por gerenciar sua única instância.
[_Singleton_](https://gist.github.com/walteralleyz/2952a7322fe2f499f2f2d9a62fa6c2ee)

A definição do padrão Builder é bem clara. Ele separa a construção de um objeto complexo de sua representação de modo que o mesmo processo de construção possa criar diferentes representações. Em outras palavras, você tem a estrutura da classe e consegue criar os objetos como se fossem um passo a passo.
[_Builder_](https://gist.github.com/walteralleyz/733632239fe7ce2b2b61e70eae66d6db)

**Padrões de Estrutura**

Um uso comum do Façade é quando temos que fazer a comunicação com um subsistema complexo. Para isso, o padrão fornece uma interface única para um conjunto de interfaces de um subsistema. O objetivo é diminuir o acoplamento no sistema ao concentrar o uso do subsistema em uma fachada, ou seja, em uma interface de nível mais elevado que torna o subsistema mais fácil de usar.
[_Facade_](https://gist.github.com/walteralleyz/776584c0a187035ce2bcea0eedaa789c)

O objetivo do Composite é compor objetos em estruturas de árvore, de um modo que possamos tratar um objeto da mesma maneira que uma única instância do mesmo tipo de objeto. Existe também uma estrutura todo-parte em um Composite: um nó na hierarquia de um Composite tem como partes integrantes de si todos os seus filhos.

Um bom exemplo são as interfaces gráficas: cada componente da tela herda de Widget e pode ter vários filhos. Com isso podemos tratar tanto um simples botão como uma janela completa do mesmo modo.
Este padrão se relaciona com o Visitor, que pode ser utilizado para realizar uma operação em um Composite e também com o Iterator, que pode ser utilizado para percorrer o Composite.
[_Composite_](https://gist.github.com/walteralleyz/d20644e136631282e5d15dcc17380315)

O padrão Adapter serve como um adaptador. Ele converte a interface de um objeto para a interface esperada por um cliente. Permite que objetos com interfaces incompatíveis comuniquem-se efetivamente.
[_Adapter_](https://gist.github.com/walteralleyz/e76e9d7f7ed6379259c5602748231ff1)

O padrão Bridge permite que possamos desacoplar uma abstração de sua implementação, gerando hierarquias gêmeas. É como se você  dividisse uma classe grande ou um conjunto de classes intimamente ligadas em duas hierarquias separadas. Literalmente cria-se uma “ponte” de ligação.
[_Bridge_](https://gist.github.com/walteralleyz/d3b6fb3e8783839a08353c970d24bd62)

De forma jocosa, o padrão Decorator permite adicionar coisas a um objeto em tempo de execução. Ou seja, ele nos permite adicionarmos responsabilidades adicionais a um objeto dinamicamente. Com isso ganhamos mais flexibilidade em detrimento ao uso de herança.

Um exemplo poderia ser em uma biblioteca de streams: um stream que pode escrever em arquivos pode ser decorado por outro que compacta os dados antes, que pode ser decorado por outro que criptografa os dados, e assim por diante.
[_Decorator_](https://gist.github.com/walteralleyz/c747dbf4dc5a72ffbbfc6d8337299168)

Um Proxy controla o acesso a um objeto, de modo a prover somente as funções permitidas a um objeto cliente. Um exemplo pode ser um proxy de proteção, que nega acesso a algumas partes de um objeto a um grupo de clientes.
[_Proxy_](https://gist.github.com/walteralleyz/42425cc1ab9527b8263cad01fcb50c00)

Um Flyweight pode ser utilizado quando temos muitos objetos que compartilham uma grande parte de seu estado. A solução é criar um Flyweight que guarda esse estado compartilhado e o estado que muda é guardado com cada objeto.
[_Flyweight_](https://gist.github.com/walteralleyz/52a0bd800ba37506346f6a29d1788bf7)

**Padrões Comportamentais**

Usamos o Strategy quando queremos ter uma família de algoritmos, de modo que possamos encapsular cada um deles , e torná-los intercambiáveis, permitindo assim que os algoritmos variem independentemente dos clientes que os utilizam.

A ideia do Strategy é encapsular esses algoritmos em uma classe separada e assim podemos trocar entre eles apenas mudando uma referência.
[_Strategy_](https://gist.github.com/walteralleyz/b1c4987ead7e7d487b85c00e89511a90)

Um Template Method é um método concreto em uma classe abstrata que define os passos de um algoritmo a ser executado, porém cada passo deve ser implementado pelas subclasses concretas. Este padrão se relaciona com um Strategy. Enquanto o Template Method cria variações entre as partes de um algoritmo usando herança, o Strategy varia o algoritmo todo usando delegação.
[_Template Method_](https://gist.github.com/walteralleyz/6f393320a68c0a36be489fb1e516a3dd)

Usar um State é necessário quando queremos que objeto altere seu comportamento quando seu estado interno muda. É como se o objeto mudasse de classe. Neste caso o estado é encapsulado em uma classe separada.

Um exemplo poderia ser um inimigo inteligente em um jogo: dependendo da situação do ambiente, seu estado muda para agressivo ou defensivo (este estado pode ser uma classe separada que controla as ações do inimigo quando ele está naquele estado).
[_State_](https://gist.github.com/walteralleyz/c2346a1393bfeb087f51c888a85beb68)

Utilizamos um Mediator quando vários objetos relacionam-se bastante. Como estas relações geram muito acoplamento, concentramos este acoplamento em uma classe mediadora. Assim, cada classe fala somente com o mediador, que repassa as mensagens para as outras classes. O mediador também concentra as regras de negócio dos objetos que ele media.
[_Mediator_](https://gist.github.com/walteralleyz/24dff6fdf20075f54a7821f917c3ca86)

Um Iterator serve para dar acesso aos elementos de uma coleção ou agregado sem expor sua implementação interna. Exemplos desse padrão são encontrados em coleções que suportam a iteração usando o comando foreach presente em algumas linguagens de programação.
[_Iterator_](https://gist.github.com/walteralleyz/159a61e7e48a9bcb460ab008cee02ca7)

O Memento é usado para externalizar o estado de um objeto sem violar o encapsulamento, de modo a poder restaurar este estado posteriormente.
[_Memento_](https://gist.github.com/walteralleyz/37e6e9e93ba22a8434a88525ff4665cc)

Com o uso do padrão Command, criamos uma maneira de encapsular requisições em classes, para que estas requisições possam ser ordenadas, enfileiradas, etc. Um uso muito comum é em logs e em distribuição de tarefas.
[_Command_](https://gist.github.com/walteralleyz/315fcb1434abb225825de674f668d142)

Através da cadeia de responsabilidades, este padrão desacopla o receptor do emissor da mensagem, criando uma cadeia de objetos em que um objeto decide se vai processar a mensagem ou passar a responsabilidade para o próximo. Este padrão se relaciona com o Composite.
[_Chain of Responsability_](https://gist.github.com/walteralleyz/2fbb04235b2ccd379f513a3a0f39cb1d)

Ele define uma espécie de gramática. Um Interpreter define uma representação para esta gramática e um interpretador para interpretar sentenças nesta gramática. Utilizado principalmente em compiladores e interpretadores (de XML, de linguagens de programação).
[_Interpreter_](https://gist.github.com/walteralleyz/63b5ea88f498ea9d68a953e38793b30b)

Um Visitor representa uma operação a ser executada em todos os elementos de uma estrutura de objetos. Este padrão se relaciona com o Composite (percorre os elementos do Composite) e Interpreter (neste caso o Visitor realiza a interpretação).

Diferença com o Iterator: enquanto o Visitor representa uma operação executada em uma estrutura de elementos, o Iterator simplesmente fornece um meio de acessar os elementos da estrutura.
[_Visitor_](https://gist.github.com/walteralleyz/c88033436cff97e6ab71b0b2d2f75267)

Um Observer define uma relação de um para muitos tal que quando algo do primeiro objeto mudar, todos os outros objetos são avisados . Isso é feito de forma a não criar acoplamento entre os objetos.
[_Observer_](https://gist.github.com/walteralleyz/769b397bde3b45f6c42463d63c5afe88)

Atenção: Esse conteúdo é apenas um compilado de materiais da internet, na tentativa de fazer um resumo usando a linguagem Java. Espero que tenham gostado.

Fontes:
Growthdev
RefactoringGuru
DevMedia
Medium
USP