RESUMO
Este artigo apresenta um estudo de caso sobre a aplicação do padrão de projeto Strategy na linguagem Java, tomando como cenário a evolução do PetHub, um sistema de gerenciamento e comercialização de produtos veterinários. O problema investigado decorre da necessidade de suportar múltiplas formas de pagamento Pix, cartão de crédito e boleto bancário, sem concentrar suas regras em uma única classe por meio de estruturas condicionais, o que tende a aumentar o acoplamento e reduzir a extensibilidade do sistema. A partir da fundamentação teórica do Strategy Pattern, é proposta uma solução orientada a objetos que encapsula cada forma de pagamento em uma estratégia independente, unificadas por uma interface comum e utilizadas por uma classe de contexto. São apresentados o diagrama de classes UML da solução, uma representação da arquitetura do sistema e a implementação completa em Java. Por fim, discutem-se as vantagens, desvantagens e os principais trade-offs envolvidos na adoção do padrão, concluindo-se que sua utilização é adequada quando há tendência real de crescimento e variação de comportamentos, ainda que introduza classes e abstrações adicionais ao projeto.
1 INTRODUÇÃO
No desenvolvimento de sistemas de software, é comum que uma aplicação precise executar diferentes comportamentos para atender às necessidades de seus usuários. Conforme o sistema evolui, novas funcionalidades podem ser adicionadas e, quando essas variações não são bem organizadas, o código tende a se tornar mais difícil de compreender, testar e manter. Nesse contexto, os Design Patterns, ou padrões de projeto, oferecem soluções reutilizáveis para problemas recorrentes no desenvolvimento de software.
Entre esses padrões está o Strategy, pertencente à categoria dos padrões comportamentais. Seu principal objetivo é permitir que diferentes algoritmos ou comportamentos sejam encapsulados separadamente, possibilitando que sejam substituídos de acordo com a necessidade da aplicação. Dessa forma, o sistema pode trabalhar com diferentes comportamentos sem concentrar todas as regras em uma única classe ou depender de uma grande quantidade de estruturas condicionais.
Neste artigo, o Strategy Pattern é aplicado em Java a partir de um estudo de caso baseado na evolução do PetHub, um sistema voltado ao gerenciamento e à comercialização de produtos para animais. Considerando uma possível evolução do sistema para permitir a realização de pedidos, surge a necessidade de trabalhar com diferentes formas de pagamento, como Pix, cartão e boleto. A implementação inadequada dessas opções poderia aumentar o acoplamento e dificultar a manutenção do sistema.
Diante desse cenário, o artigo apresenta como o Strategy Pattern pode ser utilizado para organizar os diferentes comportamentos de pagamento, demonstrando desde o problema inicial até a implementação da solução em Java. São apresentados também um diagrama de classes UML e uma representação da arquitetura de software, permitindo visualizar tanto a estrutura do padrão quanto sua aplicação dentro do sistema. Por fim, são discutidas as vantagens, desvantagens e os principais trade-offs envolvidos na utilização desse padrão.
2 O PROBLEMA: MÚLTIPLAS FORMAS DE PAGAMENTO
Sistemas de software frequentemente precisam lidar com diferentes maneiras de realizar uma mesma operação. Em uma aplicação de comércio eletrônico, por exemplo, um cliente pode escolher entre diferentes formas de pagamento, como Pix, cartão de crédito ou boleto. Embora todas tenham o mesmo objetivo, concluir o pagamento de um pedido, cada uma possui regras e comportamentos específicos.
Para exemplificar esse problema, é considerada uma possível evolução do PetHub. Inicialmente, o sistema foi desenvolvido com foco no catálogo de produtos veterinários. Entretanto, em uma futura expansão, torna-se necessário permitir que os clientes realizem pedidos e efetuem pagamentos diretamente pela aplicação.
Em um primeiro momento, a implementação poderia parecer simples: bastaria criar uma classe responsável pelo pagamento e utilizar estruturas condicionais para verificar qual forma de pagamento foi escolhida, conforme ilustrado a seguir.
public void processarPagamento(String tipo, double valor) {
if (tipo.equals("PIX")) {
// Processamento do pagamento via Pix
} else if (tipo.equals("CARTAO")) {
// Processamento do pagamento via cartão
} else if (tipo.equals("BOLETO")) {
// Processamento do pagamento via boleto
}
}
Apesar de funcionar inicialmente, essa abordagem tende a se tornar problemática conforme novas formas de pagamento são adicionadas. Se o sistema passar a aceitar outras opções, como carteiras digitais ou novos gateways de pagamento, será necessário modificar continuamente a mesma classe, aumentando sua responsabilidade e tornando o código mais difícil de manter.
Além disso, cada forma de pagamento pode possuir regras próprias. O cartão pode exigir validação dos dados e comunicação com uma operadora, enquanto o Pix pode utilizar uma API específica e o boleto pode depender da geração de um código de pagamento. Concentrar todos esses comportamentos em uma única classe aumenta o acoplamento entre o sistema e as diferentes formas de pagamento. Esse cenário resulta nos seguintes problemas:
Alta complexidade: a classe responsável pelo pagamento tende a crescer conforme novas opções são adicionadas;
Alto acoplamento: a lógica principal passa a depender diretamente das implementações de cada forma de pagamento;
Dificuldade de manutenção: alterações em uma forma de pagamento podem exigir modificações na classe central;
Baixa extensibilidade: adicionar um novo comportamento exige alterar código já existente;
Maior dificuldade de testes: diferentes regras de pagamento ficam concentradas na mesma estrutura.
Portanto, o problema não está simplesmente na existência de diferentes formas de pagamento, mas na maneira como esses comportamentos são organizados dentro do sistema. É necessário encontrar uma solução que permita separar essas regras e, ao mesmo tempo, possibilite que o sistema escolha e utilize diferentes comportamentos de pagamento sem modificar constantemente sua lógica principal. A Figura 1 ilustra essa concentração de responsabilidades.

Figura 1 – Estrutura condicional concentrada em uma única classe
Fonte: elaborado pelo autor (2026).
É nesse contexto que o Strategy Pattern se apresenta como uma alternativa para organizar esses comportamentos de forma mais flexível e independente.
3 REFERENCIAL TEÓRICO: O STRATEGY PATTERN
3.1 O que é o Strategy Pattern
O Strategy Pattern é um padrão de projeto pertencente à categoria dos padrões comportamentais. Seu objetivo é permitir que diferentes algoritmos ou comportamentos sejam definidos separadamente e possam ser utilizados de maneira intercambiável dentro de uma aplicação.
Em outras palavras, quando um sistema precisa realizar uma determinada operação de diferentes maneiras, o Strategy permite separar cada uma dessas maneiras em uma estratégia própria. A aplicação pode então escolher qual estratégia utilizar sem precisar conhecer todos os detalhes de sua implementação. No contexto do PetHub, o objetivo continua sendo realizar um pagamento; entretanto, a maneira de realizar essa operação varia de acordo com a opção escolhida pelo cliente.
3.2 Como o Strategy funciona
O funcionamento do padrão pode ser compreendido a partir de três elementos principais:
Strategy: define uma interface comum para os diferentes comportamentos que podem ser utilizados pelo sistema;
Concrete Strategies: são as implementações concretas dessa interface, cada uma contendo a lógica específica de um determinado comportamento;
Context: é o componente que utiliza uma Strategy. Ele não precisa conhecer os detalhes de como cada estratégia funciona, apenas utiliza a interface definida pelo padrão.
No estudo de caso deste artigo, a PaymentService representa o Context. Ela trabalha com a interface PaymentStrategy em vez de depender diretamente de PixStrategy, CartaoStrategy ou BoletoStrategy. Dessa forma, a estratégia pode ser alterada sem que a lógica principal do serviço precise conhecer ou implementar cada forma de pagamento.
3.3 Uma analogia para entender o Strategy
Uma maneira simples de compreender o conceito é imaginar um aplicativo de navegação. O objetivo do usuário é chegar ao destino, mas existem diferentes maneiras de fazer isso: ele pode escolher viajar de carro, de bicicleta ou de transporte público. O destino permanece o mesmo, porém o algoritmo utilizado para chegar até ele é diferente.
O aplicativo não precisa alterar toda a sua estrutura cada vez que o usuário troca o meio de transporte; ele apenas utiliza uma estratégia diferente para calcular a rota. No Strategy Pattern, a lógica é semelhante: o sistema possui um objetivo, mas existem diferentes maneiras de realizar determinada operação, e cada maneira é encapsulada em uma estratégia independente, permitindo que sejam substituídas conforme a necessidade. No caso do PetHub, o objetivo é processar um pagamento, enquanto Pix, cartão e boleto representam diferentes estratégias para realizar essa operação. Essa separação permite que novos comportamentos sejam adicionados com menor impacto sobre as partes já existentes do sistema.
4 ESTUDO DE CASO: EVOLUÇÃO DO PETHUB
4.1 Cenário
O PetHub é um sistema desenvolvido com o objetivo de facilitar o gerenciamento e a apresentação de produtos destinados a animais, podendo ser utilizado por estabelecimentos do segmento veterinário. Em sua versão inicial, o sistema possui foco no catálogo de produtos, permitindo a organização e a consulta das informações relacionadas aos itens disponíveis.
Considerando uma possível evolução da aplicação, o PetHub passaria a oferecer também a realização de pedidos e o processamento de pagamentos. Com essa expansão, seria necessário disponibilizar diferentes formas de pagamento para atender às necessidades dos clientes. Para este estudo de caso, são consideradas inicialmente três formas de pagamento: Pix, cartão de crédito e boleto bancário.
Embora todas tenham a mesma finalidade, concluir o pagamento de um pedido, cada modalidade possui regras e formas diferentes de processamento. Um pagamento via Pix pode exigir a geração e a validação de uma transação por meio de uma API, enquanto um pagamento com cartão pode exigir a comunicação com um gateway de pagamento e a validação dos dados da transação. Já o boleto possui um fluxo próprio de geração e confirmação. Assim, o sistema precisa permitir que essas diferentes regras coexistam sem que a lógica principal do processamento de pedidos fique diretamente dependente dos detalhes de cada forma de pagamento.
4.2 Problema identificado
Uma implementação inicial poderia concentrar todas as regras de pagamento em um único serviço. Nesse cenário, sempre que o cliente escolhesse uma forma de pagamento, o sistema verificaria a opção selecionada e executaria a lógica correspondente. Com poucas opções, essa abordagem poderia funcionar; entretanto, conforme o PetHub evoluísse e novas formas de pagamento fossem adicionadas, o serviço responsável pelo processamento passaria a acumular diferentes regras e estruturas condicionais.
Essa organização faz com que uma única classe seja responsável por conhecer e controlar diferentes comportamentos. Como consequência, a inclusão de uma nova modalidade de pagamento exigiria alterações no serviço existente, por exemplo, caso o PetHub passasse a aceitar uma carteira digital, seria necessário modificar novamente a lógica central para incluir esse novo comportamento. Além de dificultar a manutenção, essa abordagem aumenta o acoplamento e pode tornar os testes mais complexos, já que diferentes regras ficam concentradas no mesmo componente.
4.3 Solução proposta
Para solucionar esse problema, é aplicado o Strategy Pattern, separando cada forma de pagamento em uma estratégia independente. A ideia é criar uma interface comum, denominada PaymentStrategy, responsável por definir o comportamento que todas as estratégias de pagamento devem oferecer. A partir dela, são criadas implementações específicas para Pix, cartão e boleto.
O serviço responsável pelo pagamento utiliza a interface PaymentStrategy sem precisar conhecer os detalhes internos de cada modalidade. Dessa maneira, quando uma nova forma de pagamento se tornar necessária, uma nova estratégia pode ser criada seguindo o mesmo contrato, reduzindo a necessidade de modificar a lógica já existente. A solução proposta busca, portanto, tornar o módulo de pagamentos do PetHub mais organizado, flexível e preparado para futuras extensões, mantendo cada comportamento separado de acordo com sua responsabilidade. A Figura 2 apresenta o diagrama de classes UML da solução proposta.

Figura 2 – Diagrama de classes UML do Strategy Pattern aplicado ao PetHub
Fonte: elaborado pelo autor (2026).
5 IMPLEMENTAÇÃO DO STRATEGY PATTERN EM JAVA
Para demonstrar a aplicação do Strategy Pattern, é utilizada uma implementação simplificada do módulo de pagamentos do PetHub. O objetivo é permitir que o sistema processe diferentes formas de pagamento sem concentrar todas as regras em uma única classe. A implementação é composta por uma interface, que representa a estratégia de pagamento, por classes responsáveis pelas diferentes formas de pagamento e por uma classe de serviço, que representa o contexto responsável por utilizar a estratégia selecionada.
5.1 Interface Strategy
O primeiro passo é definir uma interface que estabeleça um comportamento comum para todas as formas de pagamento. Essa interface é denominada PaymentStrategy.
public interface PaymentStrategy {
void pagar(double valor);
}
A interface define o método pagar(), que recebe o valor da transação. Ela não determina como o pagamento será realizado essa responsabilidade fica a cargo das classes que implementam a interface. Dessa forma, qualquer nova forma de pagamento pode seguir o mesmo contrato, desde que implemente o método definido pela PaymentStrategy.
5.2 Estratégia de pagamento via Pix
A primeira implementação é responsável pelo pagamento via Pix.
public class PixStrategy implements PaymentStrategy {
@Override
public void pagar(double valor) {
System.out.println(
"Pagamento de R$ " + valor + " realizado via Pix."
);
}
}
A classe PixStrategy implementa a interface PaymentStrategy e fornece sua própria implementação do método pagar(). Em uma aplicação real, esse método poderia conter a comunicação com um serviço ou gateway de pagamentos responsável pelo processamento da transação Pix. Para manter o exemplo didático, a implementação apenas simula a operação por meio de uma mensagem no console.
5.3 Estratégia de pagamento via cartão
A segunda estratégia representa o pagamento por cartão de crédito.
public class CartaoStrategy implements PaymentStrategy {
@Override
public void pagar(double valor) {
System.out.println(
"Pagamento de R$ " + valor + " realizado via cartão."
);
}
}
Assim como na estratégia de Pix, a classe CartaoStrategy possui uma implementação específica do comportamento de pagamento. A principal diferença é que a lógica de processamento pode variar: em um sistema real, essa estratégia poderia realizar uma integração com um gateway de pagamentos ou um serviço responsável pela autorização da transação.
5.4 Estratégia de pagamento via boleto
A terceira implementação representa o pagamento por boleto bancário.
public class BoletoStrategy implements PaymentStrategy {
@Override
public void pagar(double valor) {
System.out.println(
"Boleto de R$ " + valor + " gerado para pagamento."
);
}
}
A classe BoletoStrategy também segue o contrato definido pela PaymentStrategy, mas possui um comportamento específico para essa modalidade. Nesse caso, uma aplicação real poderia utilizar um serviço externo para gerar o boleto e, posteriormente, receber a confirmação do pagamento.
5.5 Contexto: PaymentService
Depois de criar as estratégias, é necessário definir o componente que irá utilizá-las. Esse componente é representado pela classe PaymentService.
`public class PaymentService {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processarPagamento(double valor) {
strategy.pagar(valor);
}
}
`
A classe PaymentService representa o Context do Strategy Pattern. Ela possui uma referência para PaymentStrategy, mas não depende diretamente de uma implementação específica — o serviço não precisa saber se está trabalhando com Pix, cartão ou boleto. O comportamento utilizado é definido por meio do método setStrategy().
5.6 Utilizando diferentes estratégias
A aplicação pode então escolher qual estratégia será utilizada para processar um pagamento, conforme demonstrado a seguir.
`public class Main {
public static void main(String[] args) {
PaymentService paymentService = new PaymentService();
paymentService.setStrategy(new PixStrategy());
paymentService.processarPagamento(150.00);
paymentService.setStrategy(new CartaoStrategy());
paymentService.processarPagamento(250.00);
paymentService.setStrategy(new BoletoStrategy());
paymentService.processarPagamento(300.00);
}
}`
Nesse exemplo, o mesmo objeto PaymentService utiliza diferentes estratégias durante a execução. Primeiro, a estratégia de Pix é selecionada; em seguida, a estratégia de cartão é utilizada; e, posteriormente, a estratégia de boleto. O PaymentService não precisa possuir uma estrutura de if/else para determinar como cada pagamento deve ser realizado ele simplesmente trabalha com o contrato definido pela interface PaymentStrategy.
Essa separação é justamente uma das principais características do Strategy Pattern: o comportamento pode ser alterado sem que o contexto precise conhecer os detalhes de cada implementação.
5.7 Correspondência entre o código e o Strategy Pattern
O Quadro 1 relaciona a implementação apresentada aos elementos descritos na seção teórica, evidenciando como o conceito do padrão é aplicado diretamente na solução em Java.

Quadro 1 – Correspondência entre o Strategy Pattern e a implementação do PetHub
Fonte: elaborado pelo autor (2026).
6 REPRESENTAÇÃO ARQUITETURAL DO SISTEMA
Além do diagrama de classes, é importante compreender como o Strategy Pattern se insere no contexto arquitetural mais amplo do PetHub. A Figura 3 apresenta o fluxo desde a interação do usuário com o front-end até a comunicação final com o gateway de pagamento externo, evidenciando o papel do PaymentService como Context e das classes concretas como estratégias intercambiáveis.
Figura 3 – Arquitetura do módulo de pagamentos do PetHub
Fonte: elaborado pelo autor (2026).
Nessa representação, o PedidoService orquestra o fluxo do pedido e delega a execução do pagamento ao PaymentService, que por sua vez seleciona a estratégia concreta correspondente à escolha do cliente. Cada estratégia concreta é responsável por se comunicar com o gateway ou API de pagamento externo apropriado, isolando essa integração das camadas superiores da aplicação.
7 VANTAGENS, DESVANTAGENS E TRADE-OFFS
A adoção de um Design Pattern não deve ser avaliada apenas pelos benefícios que proporciona, mas também pelos custos que introduz no projeto. No caso do Strategy Pattern aplicado ao módulo de pagamentos do PetHub, é possível identificar vantagens, desvantagens e trade-offs relevantes.
7.1 Vantagens
Redução do acoplamento: o PaymentService passa a depender apenas da interface PaymentStrategy, e não das implementações concretas de cada forma de pagamento;
Extensibilidade: novas formas de pagamento podem ser adicionadas por meio de novas classes que implementam PaymentStrategy, sem necessidade de alterar o código já existente, em conformidade com o princípio Aberto/Fechado (Open/Closed Principle);
Facilidade de manutenção: cada regra de pagamento fica isolada em sua própria classe, o que reduz o risco de uma alteração impactar outras formas de pagamento;
Testabilidade: cada estratégia pode ser testada de forma isolada, sem depender da lógica das demais;
Eliminação de estruturas condicionais extensas: o padrão substitui blocos de if/else ou switch por polimorfismo, tornando o código mais legível.
7.2 Desvantagens
Aumento do número de classes: cada nova estratégia exige a criação de uma nova classe, o que pode aumentar a complexidade estrutural do projeto;
Overhead em cenários simples: quando há poucas variações de comportamento e baixa probabilidade de crescimento, o padrão pode adicionar abstrações desnecessárias;
Necessidade de gerenciamento das estratégias: o cliente do Context (ou uma fábrica) precisa saber qual estratégia concreta instanciar e associar ao contexto, o que pode exigir lógica adicional em outro ponto do sistema.
7.3 Trade-offs
O principal trade-off do Strategy Pattern está no equilíbrio entre flexibilidade e simplicidade. Ao encapsular comportamentos em classes separadas, o sistema ganha em organização e extensibilidade, mas paga o preço de uma estrutura de código mais distribuída, com mais arquivos e indireções para acompanhar.
Esse custo tende a se justificar quando existe uma expectativa real de que novas variações do comportamento no caso do PetHub, novas formas de pagamento surgirão ao longo da evolução do sistema. Em contrapartida, para cenários com poucas variações e baixa perspectiva de mudança, uma solução mais simples, mesmo que utilize estruturas condicionais, pode ser suficiente e mais direta de manter.
8 CONCLUSÃO
A aplicação do Strategy Pattern no módulo de pagamentos do PetHub demonstra como um padrão de projeto pode contribuir para a organização e a evolução de um sistema de software. Ao separar cada forma de pagamento em uma estratégia própria, o sistema deixa de concentrar diferentes comportamentos em uma única classe e passa a trabalhar com uma abstração comum.
No cenário apresentado, o PaymentService não precisa conhecer os detalhes de cada modalidade de pagamento: ele trabalha com a interface PaymentStrategy e delega a execução à estratégia selecionada. Dessa forma, novas formas de pagamento podem ser incorporadas por meio de novas implementações da estratégia, reduzindo o impacto sobre o código existente. Além da redução do acoplamento, essa abordagem favorece a manutenção e a extensibilidade do sistema, sendo especialmente útil quando diferentes comportamentos precisam ser utilizados de maneira intercambiável e tendem a crescer ou sofrer alterações ao longo da evolução da aplicação.
Entretanto, como discutido na seção anterior, a utilização de um Design Pattern não deve ser considerada uma solução universal: o Strategy também adiciona classes e abstrações ao projeto, o que pode aumentar sua complexidade quando existem poucas variações de comportamento. Sua utilização deve, portanto, estar relacionada a uma necessidade real do sistema e aos benefícios que a separação dos comportamentos pode proporcionar.
No caso do PetHub, a aplicação do padrão apresenta uma alternativa adequada para preparar o módulo de pagamentos para futuras evoluções, mantendo as diferentes regras de processamento isoladas e permitindo que novos comportamentos sejam incorporados de maneira mais organizada.
9 CONSIDERAÇÕES DO AUTOR
Ao estudar e aplicar o Strategy Pattern, uma das principais conclusões foi perceber que o problema não está simplesmente em utilizar if ou switch. Em muitos casos, essas estruturas resolvem a necessidade inicial. O problema aparece quando o sistema começa a crescer e cada nova regra exige alterações na mesma parte do código.
Foi justamente essa situação que tornou o Strategy interessante para o contexto do PetHub. Ao trabalhar com diferentes formas de pagamento, como Pix, cartão e boleto, cada modalidade pode possuir sua própria lógica de processamento. Em vez de concentrar todas essas regras em uma única classe, o padrão permite que cada comportamento seja tratado separadamente.
Essa separação também muda a forma de pensar sobre a evolução do sistema. Se futuramente o PetHub precisar aceitar uma nova forma de pagamento, a ideia é que seja possível criar uma nova estratégia sem precisar modificar toda a estrutura responsável pelo processamento. Isso reduz o acoplamento entre as partes do sistema e facilita a manutenção.
Na minha visão, esse é um dos pontos mais interessantes do Strategy: ele não existe apenas para deixar o código mais bonito, mas para facilitar mudanças que provavelmente acontecerão no futuro. Em sistemas de pagamento, isso é especialmente relevante, já que novas modalidades, serviços e integrações podem surgir ao longo do tempo.
Outro aprendizado importante foi entender que robustez está relacionada à capacidade de evolução do software. Um sistema pode funcionar perfeitamente hoje e, ainda assim, ser difícil de manter amanhã. Por isso, pensar na arquitetura considerando possíveis mudanças pode evitar que pequenas alterações se transformem em grandes problemas.
E você?
Você já precisou lidar com um código em que a quantidade de if/else começou a dificultar a manutenção?
Se você estivesse desenvolvendo um sistema com diferentes formas de pagamento, usaria o Strategy Pattern ou escolheria outra abordagem?
Quero saber como você resolveria esse problema. Compartilhe sua experiência ou opinião nos comentários!
REFERÊNCIAS
GAMMA, E.; HELM, R.; JOHNSON, R.; VLISSIDES, J. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2000.
SOMMERVILLE, I. Engenharia de software. 10. ed. São Paulo: Pearson Education do Brasil, 2019.

Top comments (0)