Padrões de projeto: quais as vantagens e por que usar?

Postado por: em 15/10/2021
padrões de design, design patterns

A publicação do livro Design Patterns, da “gangue dos quatro” (Gang of Four, ou GoF, formada pelos autores Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides) tornou-se muito rápido um exemplo na ciência da computação.

Devido ao seu conteúdo útil, o livro foi precursor em uma atual metalinguagem nos grupos de engenharia e arquitetura. A publicação fornece uma coleção de padrões de estrutura de objeto e estrutura intra-objeto, que foi acolhido da arquitetura de construção e posto levemente na programação.

Padrões de projeto: por que usar e quais vantagens eles podem oferecer?

Um padrão de projeto é uma solução previamente especificada para um problema estabelecido. A grande vantagem é que os padrões resolvem problemas triviais.

Problema estabelecido por um padrão de projeto

Muitas vezes, em um projeto, nos deparamos com um estágio em que não há mais progresso, então, algumas etapas são refeitas antes do novo início. Ao definir alguns problemas comuns, verificamos de acordo com os padrões qual solução pode melhorar o projeto.

Solução definida

Definindo e reconhecendo um problema, uma solução pode ser proporcionada por um padrão em companhia da análise do seu uso.

Projeto bem estabelecido com padrões de projeto

Princípios de projeto orientado a objetos são aplicados e demonstrados por padrões, e padrões de projeto podem oferecer mais de uma solução específica num contexto. Com isso, é possível combinar objetos e classes de modo a alcançar um objetivo.

Aplicação prática

Como referência, os exemplos serão norteados pelos padrões de projeto estabelecidos pela gangue dos quatro. Alguns padrões de projeto serão implementados e postos em prática mostrando sua base arquitetônica sólida na resolução de impedimentos que travam a evolução de um sistema.

Observer Pattern

Em qualquer projeto de larga escala, a utilização do acoplamento fraco é essencial. O vínculo entre os objetos é menor quando se aplica o Observer pattern, possibilitando um contrato intra-objeto simplificado. 

Um objeto autoriza-se a ser observado fornecendo um mecanismo onde os objetos conseguem se registar nele. No momento em que o objeto observado é alterado, ele sinaliza os objetos observadores por meio de um objeto de notificação. Não existe preocupação para o objeto Observer, ele não se preocupa em saber quais tipos de objetos estão observado nem os que o observa.

Na demonstração a seguir será implementado uma lista de clientes observáveis e esse objeto é uma representação de uma tabela no database.

Detalhamento da implementação

Notificações serão enviadas pelo objeto Customer no momento que novos clientes forem incluídos. O objeto do Customer usa um objeto RegisterCollection para implementar sua capacidade de observação. O objeto listener é uma instância de RegisterCollection, que os demais objetos conseguem usar para se registrar em Customer. Os listeners usam o método add() para se incluir na lista e Customer usa o método ding() para enviar uma mensagem para os listeners.

A não existência de listener ou a existência de milhares deles não é importante. O que chama atenção aqui são os objetos listeners não terem nenhuma interação direta ou dependência com relação a Customer. Os clientes são isolados dos listeners pela classe RegisterCollection.

Haverá um único listener nesse exemplo: um objeto Log que gera na saída as mensagens enviadas de Customer para o terminal. A instanciação dos objetos no código se dá primeiro pela criação um log e uma lista de customers usando o método add(). O passo final é incluir um usuário na lista de Customer. Quando ocorre a inclusão do cliente, é disparada uma mensagem para os listeners (assim sendo no caso atual, o Log), comunicando a respeito da inclusão do cliente.

Vá mais adiante

A quantidade de aplicações são inúmeros para o uso do Observer pattern no desenvolvimento de sistemas. Uma boa técnica com o Observer pattern é a utilização também quando uma mudança de estado é relevante, mas ainda não é reconhecido para quem será relevante, e nesse caso é possível desenvolver os listeners mais tarde e então vincular posteriormente ao objeto que será observado.

Composite pattern para fragmentar classes grandes

Utilize o composite pattern para fragmentar mega classes em classes pequenas e gerenciáveis. Analise o seguinte problema: imagine um banco de dados gigantesco, armazenando tudo que alguém queira saber sobre uma pessoa. Nesta ocasião, pense em como esse sistema é mal projetado. Nesses casos, é quase certeza de que lá existe uma mega classe terrível, chamada Customer, certamente com mais de 5.000 métodos e já ultrapassando 3.000 propriedades.

Por esse motivo, a classe apresentada vai demandar realmente o uso do Composite pattern. O Composite pattern preservaria a classe Customer, mas disporia grupos dessas 3.000 propriedades amontoadas contidas em objetos descendentes. O objeto Customer conteria na verdade a uns 100 objetos aproximadamente, cada um envolvendo outros objetos pequenos, os quais seriam capazes de ter objetos ainda menores e assim por diante.

Aplicação prática

A demonstração desta dica exemplifica como se pega uma classe Employee com muitas propriedades e a fraciona em várias classes menores, sendo que ao término da implementação ainda se tem uma única classe composta.

 

Explicando a resolução

O conceito é de tal maneira eficiente quanto simples, não se deve ter mega classes com 100 propriedades. Tenha pequenas classes em grupos, como EmployeeName e EmployeeAddress, que podem integrar em recursos maiores (neste caso a classe Employee).

Reflita na aplicabilidade e seus benefícios

A primeira boa indicação para o uso do Composite pattern é na hora em que os dados de um objeto estão dispersos em várias tabelas do banco de dados. Qualquer tabela associada deve estar em seu próprio objeto ou estrutura de dados.

O Composite pattern também proporciona o aperfeiçoamento da leitura do banco de dados. Como carregar cada sub objeto como o EmployeeAddress, exigirá uma consulta diferente, é viável fazer isso pouco a pouco. Ou melhor, em outros termos, é possível atrasar o carregamento de um sub objeto em específico, até que os dados desse objeto sejam essenciais. Isso impede que o código pegue muitas propriedades em diversas tabelas do banco de dados, quando tudo que é necessário em determinados casos é retornar o nome e sobrenome de uma pessoa.

Compensa usar padrões de projeto?

Aplicar padrões de projeto com baixo acoplamento é preferível do que ter que reescrever todo sistema a todo o momento que fizer uma modificação. Dessa maneira, estão disponíveis várias implementações diferentes de padrões de projeto que devem ser analisadas em conjunto com o problema enfrentado, aplicando assim o padrão de projeto que melhor atende aos requisitos.