19 de outubro de 2026
Impactos do uso de padrões de projeto
Impactos do Uso de Padrões de Projeto
Thalia Vilela Ferreira; Vinicius Santos Andrade
DOI: 10.22167/2675-6528-202602378
Artigo derivado de Trabalho de Conclusão de Curso (TCC), com conteúdo baseado no trabalho original do aluno e adaptado ao formato editorial da Revista E&S com apoio da ferramenta ResumeAI, solução de inteligência artificial desenvolvida pelo Instituto Pecege para síntese e organização textual.
Resumo
Padrões de projeto são soluções bem-sucedidas em diversos contextos que utilizam os conceitos de orientação a objetos para criar código flexível e reutilizável. Em desenvolvimento de software, a aplicação dessas soluções exige a compreensão de seus impactos positivos e negativos. Assim, o estudo teve como objetivo avaliar esses impactos por meio da implementação dos padrões de projeto Composite, Factory Method e Strategy, metrificando com as métricas CK os efeitos na complexidade, acoplamento e reuso. A metodologia aplicada foi quali-quantitativa, com dados obtidos pela aplicação dos padrões em um software, medindo seu estado antes e depois, e observando as vantagens e desvantagens resultantes da alteração. Como resultado, analisou-se que a complexidade diminuiu, tornando o código mais simples de trabalhar e possibilitando maior reuso. As classes ficaram mais flexíveis e puderam adaptar-se melhor à extensão dos requisitos, concluindo que o uso de padrões é recomendado quando se obtêm ganhos na complexidade dos requisitos.
Palavras-chave: Abstração; Complexidade; Flexibilidade; Objetos; Relacionamento.
1. Introdução
A evolução da programação de software marcou uma transição significativa de abordagens monolíticas para estruturas mais organizadas e modulares. Inicialmente, a codificação era realizada em blocos únicos, com desvios condicionais pontuais. Posteriormente, a programação estruturada introduziu blocos de código como condicionais, laços de repetição e funções, fragmentando a lógica em partes menores. No final dos anos 1960, o paradigma da orientação a objetos emergiu, redefinindo a estruturação dos sistemas (Eduardo Guerra, 2014).
Um sistema orientado a objetos é composto por objetos que interagem para manter um estado interno e suportar operações específicas, com o estado sendo inacessível externamente. Este paradigma envolve a criação de classes e o estabelecimento de relacionamentos entre elas, definindo a interação dos objetos em tempo de execução. Os objetos encapsulam dados e ações, permitindo que sejam estendidos ou modificados de forma independente, sem alterar outros componentes (Ian Sommerville, 2010). A abstração de conceitos é fundamental para desenvolver componentes desacoplados, promovendo maior reuso e flexibilidade do software (Eduardo Guerra, 2014). Os pilares da orientação a objetos incluem herança, encapsulamento, polimorfismo e abstração. A herança permite que uma classe filha adquira atributos e métodos de uma classe mãe, especializando seu comportamento. O encapsulamento isola a lógica e os dados, expondo apenas a interface necessária ao cliente. O polimorfismo possibilita que um objeto assuma a forma de suas abstrações, como uma superclasse ou interface (Eduardo Guerra, 2014).
A aplicação desses conceitos de orientação a objetos levou ao desenvolvimento dos padrões de projeto. Inspirados no trabalho de Christopher Alexander sobre padrões arquitetônicos, percebeu-se que a mesma lógica poderia ser aplicada ao desenvolvimento de software. Em 1994, Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides catalogaram essas soluções no livro “Padrões de projeto: soluções reutilizáveis de software orientado a objetos” (Ian Sommerville, 2010). Esses padrões representam soluções comprovadas para problemas recorrentes, facilitando a criação de código flexível e reutilizável em diversos contextos.
No entanto, a mera existência de uma solução não garante sua aplicação eficaz. Ao utilizar padrões de projeto no desenvolvimento de software, é essencial compreender os impactos positivos e negativos que sua implementação pode gerar. A escolha de um padrão deve ser criteriosa, alinhada aos requisitos e ao contexto específico do software, considerando as vantagens e desvantagens para uma tomada de decisão informada. Existe uma lacuna prática na compreensão aprofundada de como esses padrões se manifestam em termos de métricas de qualidade de software, especialmente em ambientes de desenvolvimento contemporâneos.
Diante desse cenário, a justificativa para este estudo reside na necessidade de fornecer uma avaliação empírica dos impactos da aplicação de padrões de projeto. Compreender como a utilização de padrões como Composite, Factory Method e Strategy afeta o acoplamento, a complexidade, o reuso e a flexibilidade de um software é crucial para desenvolvedores. Este trabalho tem como objetivo avaliar o impacto da utilização dos padrões de projeto em um software, com as vantagens e desvantagens de sua utilização em acoplamento, complexidade, reuso e principalmente flexibilidade, com a motivação de apresentá-los no contexto comum ao desenvolvimento de software para web com a construção de APIs REST, frameworks e consultas ao banco de dados.
2. Material e Métodos
A pesquisa realizada caracterizou-se como exploratória, com o propósito de explicitar o impacto do uso de padrões de projeto no desenvolvimento de software. Adotou-se uma abordagem quali-quantitativa, combinando a análise de informações bibliográficas com a medição de métricas em um estudo de caso prático, conforme a metodologia descrita a seguir.
Inicialmente, conduziu-se uma pesquisa bibliográfica abrangente para levantar informações sobre os padrões de projeto, incluindo sua intenção, motivação, estrutura, benefícios e desvantagens. Adicionalmente, buscou-se conhecimento sobre métodos para metrificar a complexidade e o acoplamento em aplicações orientadas a objetos. Para esta etapa, foram consultados livros e artigos consolidados na área, sem restrição de data de publicação, dada a estabilidade dos conceitos de padrões de projeto ao longo do tempo (Gamma et al., 2008; Sommerville, 2010).
O objeto empírico do estudo foi um software desenvolvido especificamente para uma plataforma de e-learning. A construção inicial do software foi realizada sem a aplicação de padrões de projeto, focando apenas na separação mínima de classes. Este estado inicial permitiu o estabelecimento de parâmetros de referência para complexidade e acoplamento, antes da intervenção metodológica.
Os requisitos do projeto foram definidos com base na experiência da autora em plataformas de e-learning. Incluíram a gestão de cursos, onde um curso é composto por módulos com diferentes tipos de conteúdo, como vídeo, texto, quiz e áudio, e a organização de cursos em trilhas. Também foi considerado um sistema de progressão não linear, que libera módulos com base no desempenho do aluno em quizzes.
O desenvolvimento do software foi realizado utilizando a linguagem de programação Java, na versão 17. Empregou-se o framework Spring, versão 6.2.5, em conjunto com Spring Boot, versão 3.4.4, para facilitar o desenvolvimento e o gerenciamento de dependências. Para a interação com o banco de dados, utilizou-se Spring Data MongoDB, versão 3.4.4, e a biblioteca Lombok, versão 1.18.36, para geração de código repetitivo.
A arquitetura do software foi organizada em camadas, dividindo as classes em pacotes específicos: `Api` para exposição de endpoints REST, `client` para chamadas a serviços externos (não implementados), `entity` para entidades de banco de dados, `enumeration` para valores fixos, `repository` para acesso ao banco de dados e `service` para a lógica de negócios. O banco de dados utilizado foi o MongoDB, versão 7.0, executado em um container Docker, versão 4.28.0, com WSL 2.6.3.0 e Ubuntu 22.04.
Com base na análise do código do projeto e nos requisitos, foram selecionados e implementados os padrões de projeto Factory Method, Composite e Strategy. A aplicação desses padrões foi realizada sem outras modificações no código, visando isolar o impacto direto de sua introdução. O padrão Factory Method foi aplicado para a criação parametrizada de objetos de conteúdo, como vídeo, quiz, áudio e texto, que são salvos na coleção de conteúdos e fazem parte da classe Conteúdo.
O padrão Composite foi utilizado para tratar objetos simples e compostos de forma uniforme, especificamente na consulta de atividades de um aluno, onde trilhas e cursos foram modelados para serem tratados de maneira similar. O padrão Strategy foi empregado na funcionalidade de progresso do aluno, para aplicar diferentes algoritmos com base nas notas obtidas em quizzes, permitindo a seleção dinâmica do comportamento.
Para metrificar as alterações no software, foram utilizadas as métricas de Chidamber e Kemerer (CK), propostas em 1994, com foco em orientação a objetos. As métricas empregadas foram: Métodos Ponderados por Classe (WMC), para avaliar a complexidade de cada classe; Profundidade da Árvore de Herança (DIT), para medir o número de níveis na árvore de herança; Número de Filhos (NOC), para quantificar as subclasses de uma classe; Acoplamento entre Classes de Objetos (CBO), para verificar o acoplamento entre classes; e Resposta para uma Classe (RFC), para medir o número de métodos que podem ser executados em resposta a uma mensagem (Sommerville, 2010).
A coleta de dados ocorreu em duas fases. Primeiramente, realizou-se uma medição das métricas CK no software em seu estado inicial, antes da aplicação dos padrões de projeto, utilizando a análise estática da biblioteca CK Metrics adicionada ao projeto. Em seguida, após a implementação dos padrões Factory Method, Composite e Strategy, uma nova medição das mesmas métricas foi efetuada. A análise dos dados consistiu na comparação dos valores das métricas obtidos antes e depois da aplicação dos padrões.
3. Resultados e Discussão
A aplicação de padrões de projeto em um software de e-learning foi avaliada com o objetivo de analisar seus impactos em métricas de qualidade, como complexidade, acoplamento, reuso e flexibilidade. Os resultados obtidos, por meio da aplicação dos padrões Composite, Factory Method e Strategy e da medição com as métricas CK (Chidamber e Kemerer), revelaram transformações significativas na estrutura e no comportamento do código. A análise comparativa entre o estado inicial do software e sua versão após a implementação dos padrões permitiu identificar vantagens e desvantagens práticas, alinhando-se à literatura e fornecendo uma base empírica para a tomada de decisão em projetos de desenvolvimento.
Levantamento Bibliográfico
Os padrões de projeto, conforme a literatura, são soluções consagradas que utilizam os princípios da orientação a objetos para desenvolver código flexível e reutilizável. Cada padrão é caracterizado por um nome, um problema que busca resolver, uma solução estrutural e as consequências de sua aplicação, que incluem vantagens e desvantagens (Gamma et al, 2008). Eles são categorizados em criacionais, estruturais e comportamentais, cada um abordando diferentes aspectos da criação, organização ou interação de objetos. A essência desses padrões reside na promoção de flexibilidade, reusabilidade e desacoplamento, alcançados por meio do uso de abstrações, herança e composição, que se manifestam no software através do polimorfismo (Gamma et al, 2008).
O padrão Factory Method, de categoria criacional, é empregado para delegar a criação de objetos a subclasses, permitindo que estas decidam qual objeto instanciar. Sua flexibilidade reside na capacidade de implementar qualquer abstração de produto e adaptar a estrutura do padrão aos requisitos específicos do software, sempre delegando a instanciação de classes concretas para suas subclasses (Gamma et al, 2008). Contudo, uma desvantagem notável é a necessidade de criar uma subclasse de Creator para cada instância de Product, o que pode aumentar a complexidade e comprometer a manutenibilidade. A parametrização da criação por identificador pode mitigar essa questão, mas pode introduzir condicionais excessivas, diminuindo o desacoplamento entre as classes Factory e Product (Gamma et al, 2008).
O padrão Composite, de natureza estrutural, é utilizado para tratar objetos simples e compostos de maneira uniforme, organizando-os em uma estrutura de árvore. Uma interface comum permite que tanto as folhas (objetos simples) quanto os ramos (composições) implementem o mesmo método, utilizando o polimorfismo para um tratamento consistente (Gamma et al, 2008). Entre suas vantagens, destaca-se a redução da complexidade da aplicação, pois os dois tipos de objetos são manipulados de forma uniforme, reforçando o encapsulamento. A simplicidade de adicionar novas subclasses também é um benefício. No entanto, uma desvantagem surge quando os requisitos exigem restrições de tipo, tornando difícil a aplicação do padrão sem a necessidade de checagens de tipo constantes (Gamma et al, 2008).
Por sua vez, o padrão Strategy, um padrão comportamental, é aplicado quando uma classe principal precisa utilizar diversos algoritmos. Estes algoritmos são encapsulados em classes separadas que implementam uma interface comum, permitindo que o comportamento seja alterado em tempo de execução (Gamma et al, 2008). A principal vantagem é a capacidade de alterar algoritmos de forma independente, tornando-os mais compreensíveis e flexíveis, além de eliminar condicionais na classe principal. Em contrapartida, suas desvantagens incluem a criação de um número elevado de classes, o que pode aumentar a complexidade da leitura do código, a necessidade de tratar atributos nulos e o fato de que o cliente precisa conhecer as diferentes estratégias para selecionar a correta, o que pode diminuir o acoplamento entre elas. Além disso, algumas classes concretas podem não utilizar todas as informações recebidas, levando à manutenção de dados desnecessários (Gamma et al, 2008).
As métricas de Chidamber e Kemerer (CK) foram empregadas para quantificar os impactos da aplicação dos padrões. O WMC (Weighted Methods per Class) mede a complexidade de uma classe pela soma das complexidades de seus métodos; valores altos indicam menor legibilidade e reuso (Ian Sommerville, 2010). O DIT (Depth of Inheritance Tree) indica o número de níveis na árvore de herança; maior profundidade implica maior complexidade de projeto (Ian Sommerville, 2010). O NOC (Number of Children) avalia o número de subclasses, com valores altos sugerindo maior reuso, mas também maior complexidade de entendimento (Ian Sommerville, 2010). O CBO (Coupling Between Objects) verifica o acoplamento entre classes; valores maiores indicam maior dependência (Ian Sommerville, 2010). Por fim, o RFC (Response For a Class) mede o número de métodos que podem ser executados em resposta a uma mensagem; quanto maior, mais complexa a classe (Ian Sommerville, 2010).
Aplicação dos padrões de projeto
Na funcionalidade de consulta das atividades de um aluno, especificamente no método `buscarCursosETrilhasPorAluno`, identificou-se a necessidade de tratar a distinção entre trilhas e cursos. Uma trilha é composta por cursos, e sua carga horária é a soma das cargas horárias dos cursos que a compõem, enquanto um curso possui sua própria carga horária. Inicialmente, o mapeamento para a classe `Aprendizado` exigia que, se o objeto fosse do tipo Curso, o atributo `módulos` fosse preenchido, e se fosse do tipo Trilha, o atributo `cursos` fosse preenchido. Essa abordagem inicial resultava em um código mais complexo e menos flexível devido à necessidade de diferenciação explícita e conversão de tipos.
A aplicação do padrão Composite permitiu tratar os objetos Curso e Trilha de forma unificada, eliminando a necessidade da classe intermediária `Aprendizado` e dos métodos de conversão de tipos. Com essa abordagem, o código tornou-se menos complexo e mais flexível, pois a manipulação dos objetos pôde ser realizada através de uma interface comum. O uso do Composite foi específico para duas abstrações e um único tipo de composição, o que evitou uma generalização excessiva. Além disso, os requisitos do projeto não impuseram restrições de tipo que pudessem manifestar as desvantagens do padrão, como a dificuldade de restringir classes quando apenas alguns tipos são permitidos, conforme descrito na literatura.
Para a funcionalidade de progressão do aluno, que envolvia a liberação de módulos com base no desempenho em quizzes, o padrão Strategy foi aplicado. A lógica de processamento do desempenho, que gerava mensagens diferentes para cada faixa de nota (por exemplo, desbloquear o próximo módulo para notas acima de 80%), foi dividida entre classes de estratégia. Essa divisão reduziu as validações condicionais na classe principal, tornando-a menos complexa e mais fácil de compreender. Os algoritmos puderam ser alterados separadamente, sem afetar a classe principal, o que aumentou a flexibilidade do sistema e permitiu a criação simples de novos algoritmos.
No entanto, a aplicação do padrão Strategy também evidenciou algumas das desvantagens apontadas pela literatura. Observou-se que algumas classes de estratégia não utilizavam todas as informações passadas, como o objeto `módulo`, que era transmitido a todas as estratégias, mas usado apenas por uma delas. Além disso, a implementação do padrão exigiu a criação de mais código para a estrutura do padrão do que para a própria regra de negócio. A classe cliente, responsável por selecionar a estratégia correta, precisou manter uma lista de referências a todas as classes de estratégia concretas, o que implica um conhecimento prévio das estratégias disponíveis e uma dependência explícita, diminuindo o desacoplamento entre essas classes.
A criação de objetos de conteúdo, como vídeo, quiz, áudio e texto, foi otimizada com a aplicação do padrão Factory Method parametrizado. Inicialmente, o método de criação de conteúdo era complexo, com condicionais para cada tipo de mídia. Com o Factory Method, a classe Factory foi criada para receber o tipo de conteúdo e os dados necessários, delegando a criação do objeto específico a um construtor apropriado. Essa abordagem simplificou significativamente o método de criação, tornando-o mais legível e menos propenso a erros, pois a lógica de instanciação foi centralizada e parametrizada por tipo.
Apesar da simplificação inicial, a aplicação do Factory Method revelou uma desvantagem potencial: a classe Factory, embora mais simples, pode se tornar mais complexa à medida que novos tipos de conteúdo são adicionados ao projeto. Cada novo tipo de mídia exigiria uma nova condicional na classe Factory, aumentando sua dificuldade de manutenibilidade e sua complexidade interna. Isso demonstra que, embora o padrão resolva o problema da criação de objetos, ele pode transferir a complexidade para a própria fábrica se não for cuidadosamente projetado para lidar com a extensibilidade de forma mais dinâmica, como através de um registro de fábricas.
Comparação de Métricas
A análise das métricas CK antes e depois da aplicação dos padrões revelou impactos distintos. Em relação ao WMC (Weighted Methods per Class), observou-se uma diminuição em todos os casos: de 7 para 3 no Factory Method, de 10 para 9 no Composite e de 4 para 2 no Strategy. Essa redução indica que a complexidade das classes diminuiu, tornando o código mais bem distribuído e, consequentemente, mais simples de trabalhar e com maior potencial de reuso. A diminuição do WMC é um indicador positivo de melhoria na legibilidade e manutenibilidade do software.
Os indicadores DIT (Depth of Inheritance Tree) e NOC (Number of Children) não apresentaram alterações significativas em nenhuma das aplicações dos padrões. Para o Factory Method, o DIT permaneceu em 1 e o NOC em 0. Para o Composite, o DIT manteve-se em 1 e o NOC em 0. Da mesma forma, para o Strategy, o DIT e o NOC permaneceram inalterados em 1 e 0, respectivamente. Isso ocorreu porque as classes avaliadas não tiveram modificações relacionadas à herança ou à alteração de seus métodos de forma a impactar esses indicadores, focando a simplificação na lógica interna e na distribuição de responsabilidades.
A métrica RFC (Response For a Class) apresentou variações. No padrão Factory Method, houve uma grande diminuição, passando de 32 para 14. Isso se deve ao fato de que a classe passou a executar menos métodos diretamente, pois a criação de objetos foi delegada à Factory. No Composite, o RFC teve um leve aumento, de 48 para 49, o que é esperado, pois foram adicionados métodos para generalizar o tratamento de objetos. No padrão Strategy, o RFC permaneceu estável em 24, indicando que o número de métodos que podem ser executados em resposta a uma mensagem não foi alterado significativamente.
Quanto ao CBO (Coupling Between Objects), também foram observadas variações. No Factory Method, houve um ganho em relação ao acoplamento, com uma diminuição de 14 para 12. Embora a dependência com a classe Factory tenha sido adicionada, a classe passou a chamá-la apenas para a criação de objetos, evitando a montagem de objetos com métodos setters, o que reduziu o acoplamento geral. No Strategy, o CBO aumentou de 9 para 10, pois a classe passou a chamar mais dois métodos da interface do padrão, que representa uma dependência externa. Para o padrão Composite, o CBO teve um leve aumento de 13 para 14, mas o motivo exato dessa variação não foi identificado no estudo original.
Em síntese, a aplicação dos padrões de projeto demonstrou impactos positivos na flexibilidade e na capacidade de expansão do software, facilitando a adição de novas classes e a manutenção. A pesquisa evidenciou que os padrões permitem a criação de estruturas adaptáveis para resolver problemas específicos, não sendo soluções fixas. O uso do Factory Method, por exemplo, pode simplificar a criação de objetos, mas exige atenção à complexidade da classe Factory em si. O padrão Composite provou ser eficaz na criação de estruturas que podem ser carregadas com dados do banco e manipuladas recursivamente com polimorfismo, com a vantagem de poder crescer com a adição de mais métodos na interface.
Os padrões, ao se basearem nos princípios de herança, polimorfismo e abstração da orientação a objetos, tornam o código mais compreensível após uma análise de sua estrutura, exigindo, contudo, um conhecimento prévio da solução proposta. As desvantagens observadas incluem o aumento do número de classes e a necessidade de avaliar se os requisitos do projeto justificam a complexidade adicional introduzida pelos padrões, ou se refatorações mais simples poderiam alcançar ganhos semelhantes. A aplicação do padrão Strategy, por exemplo, pode ser particularmente benéfica quando alinhada às boas práticas do SOLID, promovendo a separação de responsabilidades e a flexibilidade na alteração de algoritmos.
4. Conclusão
O presente estudo avaliou o impacto da utilização dos padrões de projeto Composite, Factory Method e Strategy em um software, buscando compreender suas vantagens e desvantagens em termos de acoplamento, complexidade, reuso e flexibilidade, com foco no contexto de desenvolvimento de software para web. Verificou-se que a aplicação desses padrões promoveu uma redução significativa na complexidade das classes, conforme indicado pela diminuição do WMC (Weighted Methods per Class) em todos os casos analisados. O padrão Composite, ao unificar o tratamento de objetos simples e compostos, tornou o código mais flexível e menos complexo, eliminando a necessidade de classes intermediárias. O Factory Method simplificou a criação de objetos, centralizando a lógica de instanciação e reduzindo o RFC (Response For a Class) e o CBO (Coupling Between Objects) na classe cliente. Por sua vez, o padrão Strategy contribuiu para a redução de validações condicionais na classe principal, aumentando a flexibilidade na alteração de algoritmos e tornando-os mais compreensíveis. Os indicadores DIT (Depth of Inheritance Tree) e NOC (Number of Children) permaneceram estáveis, sugerindo que as modificações se concentraram na lógica interna e na distribuição de responsabilidades, sem alterar a hierarquia de herança.
A principal contribuição deste trabalho reside na oferta de uma avaliação empírica dos efeitos dos padrões de projeto em métricas de qualidade de software, fornecendo subsídios práticos para desenvolvedores na tomada de decisão sobre sua aplicação. Observou-se que, embora os padrões tragam ganhos em flexibilidade e capacidade de expansão, eles podem introduzir desvantagens, como o aumento do número de classes ou a transferência da complexidade para a própria fábrica, no caso do Factory Method, ou a necessidade de o cliente conhecer as estratégias específicas, no caso do Strategy. Tais limitações reforçam a importância de uma análise criteriosa dos requisitos do projeto para justificar a complexidade adicional. Sugere-se que estudos futuros explorem a aplicação desses padrões em conjunto com técnicas de refatoração e as boas práticas do SOLID, a fim de otimizar ainda mais a separação de responsabilidades e a manutenibilidade do código, avaliando se refatorações mais simples poderiam alcançar ganhos semelhantes em contextos específicos.
Referências Bibliográficas
GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2008.
GUERRA, E. Design patterns com Java: projeto orientado a objetos guiado por padrões. São Paulo: Novatec, 2010.
SOMMERVILLE, I.; SIQUEIRA, F. Engenharia de software. São Paulo: Pearson, 2010.
Artigo oriundo de Trabalho de Conclusão de Curso da Especialização em Engenharia de Software do MBA USP/Esalq
Para saber mais sobre o curso, clique aqui e acesse a plataforma MBX Academy

