Menu
Coddy logo textTech

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.

challenge icon

Desafio

Médio

Implemente uma nova estratégia BitcoinPayment para o nosso sistema de compras.

Sua tarefa é:

  1. 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: Y onde X é o valor e Y é o endereço da carteira
    • O método pay deve retornar True após a impressão
  2. 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()
quiz iconTeste seus conhecimentos

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