Padrão Strategy
Parte da seção Object Oriented Programming do Journey de Python da Coddy — lição 48 de 64.
O Padrão Strategy define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Você pode alternar algoritmos em tempo de execução sem alterar o código do cliente.
Aqui estão classes de estratégia simples para diferentes métodos de pagamento:
class CreditCard:
def pay(self, amount):
return f"Paid ${amount} with Credit Card"
class PayPal:
def pay(self, amount):
return f"Paid ${amount} with PayPal"
class Bitcoin:
def pay(self, amount):
return f"Paid ${amount} with Bitcoin"Cada estratégia implementa o mesmo método (pay) mas com um comportamento diferente.
Crie uma classe de contexto que utiliza estratégias:
class ShoppingCart:
def __init__(self):
self.total = 0
self.payment_strategy = None
def add_item(self, price):
self.total += price
def set_payment_strategy(self, strategy):
self.payment_strategy = strategy
def checkout(self):
return self.payment_strategy.pay(self.total)A classe context pode alternar entre diferentes estratégias de pagamento.
Use o padrão strategy:
cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)
# Use a estratégia de cartão de crédito
cart.set_payment_strategy(CreditCard())
print(cart.checkout())
# Mude para a estratégia do PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())Crie outro exemplo com estratégias de ordenação:
class BubbleSort:
def sort(self, data):
return f"Bubble sorted: {sorted(data)}"
class QuickSort:
def sort(self, data):
return f"Quick sorted: {sorted(data)}"
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def sort_data(self, data):
return self.strategy.sort(data)
# Use diferentes estratégias de ordenação
numbers = [3, 1, 4, 1, 5]
sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))
sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))Saída:
Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]Ponto Chave: O Padrão Strategy permite que você troque algoritmos em tempo de execução. Defina diferentes estratégias com a mesma interface e, em seguida, deixe a classe de contexto escolher qual delas usar. Isso torna seu código flexível e fácil de estender com novos algoritmos sem alterar o código existente.
Desafio
MédioImplemente uma nova estratégia BitcoinPayment para o nosso sistema de compras.
Sua tarefa é:
- Criar uma classe BitcoinPayment que implemente PaymentStrategy
- Ela deve aceitar um wallet_address no construtor
- O método pay deve imprimir exatamente:
Paying $X using Bitcoin wallet: Yonde X é o valor e Y é o endereço da carteira - O método pay deve retornar True após a impressão
- Escrever uma função main que:
- Crie um carrinho de compras
- Adicione um laptop custando $1200 e fones de ouvido custando $100 ao carrinho
- Crie um BitcoinPayment com o endereço de carteira "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
- Defina esta estratégia de pagamento no carrinho
- Chame o método checkout
O código inicial já inclui if __name__ == "__main__": na parte inferior — você não precisa adicioná-lo. Esta é uma convenção do Python que garante que sua função main() só seja executada quando o arquivo for executado diretamente (não quando for importado por outro módulo). Basta definir sua função main() e o bloco fornecido a chamará automaticamente.
Siga a mesma estrutura mostrada nos exemplos da lição.
Folha de consulta
O Padrão Strategy define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Você pode alternar algoritmos em tempo de execução sem alterar o código do cliente.
Crie classes de estratégia com a mesma interface:
class CreditCard:
def pay(self, amount):
return f"Paid ${amount} with Credit Card"
class PayPal:
def pay(self, amount):
return f"Paid ${amount} with PayPal"
class Bitcoin:
def pay(self, amount):
return f"Paid ${amount} with Bitcoin"Crie uma classe de contexto que utiliza estratégias:
class ShoppingCart:
def __init__(self):
self.total = 0
self.payment_strategy = None
def add_item(self, price):
self.total += price
def set_payment_strategy(self, strategy):
self.payment_strategy = strategy
def checkout(self):
return self.payment_strategy.pay(self.total)Use o padrão strategy:
cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)
# Use credit card strategy
cart.set_payment_strategy(CreditCard())
print(cart.checkout())
# Switch to PayPal strategy
cart.set_payment_strategy(PayPal())
print(cart.checkout())Outro exemplo com estratégias de ordenação:
class BubbleSort:
def sort(self, data):
return f"Bubble sorted: {sorted(data)}"
class QuickSort:
def sort(self, data):
return f"Quick sorted: {sorted(data)}"
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def sort_data(self, data):
return self.strategy.sort(data)Experimente você mesmo
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number, expiry_date, cvv):
self.card_number = card_number
self.expiry_date = expiry_date
self.cvv = cvv
def pay(self, amount):
print(f"Paying ${amount} using Credit Card: {self.card_number}")
return True
class PayPalPayment(PaymentStrategy):
def __init__(self, email, password):
self.email = email
self.password = password
def pay(self, amount):
print(f"Paying ${amount} using PayPal account: {self.email}")
return True
class ShoppingCart:
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item, price):
self.items.append({"item": item, "price": price})
def set_payment_strategy(self, payment_strategy):
self.payment_strategy = payment_strategy
def checkout(self):
total = sum(item["price"] for item in self.items)
if self.payment_strategy:
return self.payment_strategy.pay(total)
else:
raise ValueError("No payment strategy set")
# Crie sua classe de estratégia BitcoinPayment aqui
if __name__ == "__main__":
main()Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosO Parâmetro selfMétodosAtributosMétodo Construtor (__init__)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Função super()Sobrescrita de MétodoHerança MúltiplaOrdem de Resolução de MétodosRecapitulação - Hierarquia de Funcionários7Métodos Especiais
Introdução aos Métodos MágicosSobrecarga de OperadoresMétodos Mágicos de ContêinerRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução a Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy2Decoradores
Introdução aos DecoradoresDecorador de PropriedadeDecorador de Método EstáticoDecorador de Método de Classe5Polimorfismo
Sobrescrita de Método RevisitadaDuck TypingClasses e Métodos AbstratosDesign de InterfacesRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição vs HerançaMixinsMétodos Estáticos e de ClasseDecoradores de ClasseGerenciadores de Contexto11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Propriedades de Classe
Variáveis de Instância vs de ClasseDecoradores de PropriedadeAtributos PrivadosRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Membros Públicos, Protegidos e PrivadosModificadores de AcessoOcultação de InformaçãoProperty Decorators AvançadosRecapitulação - Sistema de Registro de Alunos12Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário