Article image
Douglas Silva
Douglas Silva30/09/2024 20:49
Compartilhe

Padrão de Projeto Strategy: A Arte de Trocar Comportamentos

  • #Kotlin
  • #Design Patterns

Venho apresentar para vocês um Padrão de Projeto que pode te ajudar a tornar alguns problemas difíceis em fáceis 😁

Muitas vezes, durante o desenvolvimento de software, nos deparamos com uma situação onde precisamos implementar diferentes comportamentos para um mesmo método ou função, e isso pode se tornar um verdadeiro caos. Seja para calcular um desconto, validar um pedido ou até mesmo implementar um jogo, a mudança constante de regras e condições pode deixar o código confuso e difícil de manter.

É exatamente aqui que entra o Design Pattern Strategy! Com ele, podemos definir uma família de algoritmos e torná-los intercambiáveis. Dessa forma, conseguimos alterar o comportamento de um método ou uma classe sem precisar alterar o código existente, tornando-o mais organizado, flexível e fácil de dar manutenção.

O que é o Padrão Strategy? 📚

O Strategy é um padrão comportamental que define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Em outras palavras, ele permite que você escolha qual comportamento (ou estratégia) um objeto deve ter em tempo de execução.

Esse padrão é particularmente útil quando você tem múltiplas variações de um comportamento e não quer ficar enchendo o código de de if-else ou switch-case. Com o Strategy, você separa cada comportamento em sua própria classe e usa essas classes de maneira flexível. Um exemplo seria um sistema estratégico de pagamento para uma sorveteria. 🚀

Sorveteria Estratégica 🍦

Vamos continuar com o exemplo da sorveteria. Suponha que o sistema de pagamento da sorveteria foi inicialmente projetado apenas para aceitar dinheiro. Então, à medida que a loja cresceu, foi preciso aceitar cartões de crédito e QR Codes. Mas, em vez de encher o código de condicionais como:

if (formaDePagamento == "dinheiro") {
  // Processa pagamento em dinheiro
} else if (formaDePagamento == "cartaoCredito") {
  // Processa pagamento com cartão de crédito
} else if (formaDePagamento == "qrCode") {
  // Processa pagamento com QR Code
}

A ideia é usar o padrão Strategy para separar cada forma de pagamento em uma classe distinta e deixar que o sistema escolha qual estratégia usar no momento certo.

Passo a Passo de Implementação 💻

1 - Criar a Interface da Estratégia: Primeiro, definimos uma interface PagamentoStrategy que terá um método para processar o pagamento:

interface PagamentoStrategy {
  fun processarPagamento(valor: Double)
}

2 - Implementar as Estratégias Concretas: Em seguida, criamos uma classe para cada tipo de pagamento que implementa a interface PagamentoStrategy.

class PagamentoDinheiro : PagamentoStrategy {
  override fun processarPagamento(valor: Double) {
      println("Pagamento de R$$valor realizado em dinheiro.")
  }
}

class PagamentoCartaoCredito : PagamentoStrategy {
  override fun processarPagamento(valor: Double) {
      println("Pagamento de R$$valor realizado com cartão de crédito.")
  }
}


class PagamentoQRCode : PagamentoStrategy {
  override fun processarPagamento(valor: Double) {
      println("Pagamento de R$$valor realizado com QR Code.")
  }
}

3 - Criar o Contexto: Agora, criamos a classe Pedido que vai usar essas estratégias. Ela tem uma referência para a PagamentoStrategy e um método para definir qual estratégia será usada.

class Pedido {
  private var estrategiaPagamento: PagamentoStrategy? = null

  fun definirEstrategiaPagamento(estrategia: PagamentoStrategy) {
      this.estrategiaPagamento = estrategia
  }

  fun pagar(valor: Double) {
      estrategiaPagamento?.processarPagamento(valor)
  }
}

4 - Usar o Padrão na Prática: Finalmente, no momento em que o cliente decide pagar, escolhemos qual estratégia usar e executamos o pagamento.

fun main() {
  val pedido = Pedido()

  println("Cliente 1 deseja pagar em dinheiro:")
  pedido.definirEstrategiaPagamento(PagamentoDinheiro())
  pedido.pagar(20.0) // "Pagamento de R$20.0 realizado em dinheiro."

  println("\nCliente 2 deseja pagar com cartão de crédito:")
  pedido.definirEstrategiaPagamento(PagamentoCartaoCredito())
  pedido.pagar(45.0) // "Pagamento de R$45.0 realizado com cartão de crédito."

  println("\nCliente 3 deseja pagar com QR Code:")
  pedido.definirEstrategiaPagamento(PagamentoQRCode())
  pedido.pagar(30.0) // "Pagamento de R$30.0 realizado com QR Code."
}

O método definirEstrategiaPagamento permite que você troque a estratégia de pagamento a qualquer momento. Dessa forma, o pedido sabe como processar o pagamento sem depender de condicionais.

Benefícios do Padrão Strategy 📊

  • Flexibilidade: Você pode adicionar novas estratégias (novas formas de pagamento, no nosso exemplo) sem alterar o código existente.
  • Reuso de Código: Como cada comportamento é encapsulado em uma classe separada, você pode reutilizar essas estratégias em outros lugares do sistema.
  • Separação de Responsabilidade: A lógica de pagamento é separada em classes distintas, tornando o código mais legível e fácil de manter.
  • Facilidade de Teste: Como as estratégias são independentes, você pode testá-las de forma isolada.

Conclusão 📍

O padrão de projeto Strategy nos ajuda a organizar comportamentos que podem variar em um sistema, como diferentes formas de pagamento em uma sorveteria. Ele elimina a necessidade de usar condicionais para tratar variações, permitindo que você adicione novos comportamentos de maneira limpa e elegante.

Com a implementação de Strategy, a sua sorveteria não só estará pronta para aceitar qualquer forma de pagamento atual, como também estará preparada para qualquer método futurístico que possa surgir, como pagamento via criptomoedas ou reconhecimento facial. Tudo sem precisar reescrever o código principal!

Então, da próxima vez que você estiver enfrentando um problema com muitos comportamentos variáveis, lembre-se do Strategy e da nossa sorveteria! 🍦

Referencia 📚

https://refactoring.guru/pt-br/design-patterns/strategy

Compartilhe
Comentários (0)