Menu
Coddy logo textTech

Паттерн Strategy

Часть раздела Объектно-ориентированное программирование путешествия по Python на Coddy. Урок 48 из 64.

Паттерн Strategy определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Вы можете переключать алгоритмы во время выполнения, не изменяя клиентский код.

Вот простые классы стратегий для разных способов оплаты:

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"

Каждая стратегия реализует один и тот же метод (pay), но с разным поведением.

Создай контекстный класс, который использует стратегии:

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)

Контекстный класс может переключаться между разными стратегиями оплаты.

Используйте паттерн strategy:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# Использовать стратегию кредитной карты
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# Переключиться на стратегию PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())

Создайте ещё один пример со стратегиями сортировки:

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)

# Используйте разные стратегии сортировки
numbers = [3, 1, 4, 1, 5]

sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))

sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))

Вывод:

Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]

Ключевой момент: паттерн Strategy позволяет переключать алгоритмы во время выполнения. Определите разные стратегии с одним и тем же интерфейсом, а затем позвольте классу контекста выбрать, какую из них использовать. Это делает ваш код гибким и позволяет легко расширять его новыми алгоритмами без изменения существующего кода.

challenge icon

Задание

Средне

Реализуйте новую стратегию BitcoinPayment для нашей системы shopping.

Ваша задача:

  1. Создать class BitcoinPayment, реализующий PaymentStrategy
    • Он должен принимать wallet_address в конструкторе
    • Метод pay должен выводить точно: Paying $X using Bitcoin wallet: Y, где X — это сумма, а Y — адрес кошелька
    • Метод pay должен возвращать True после вывода сообщения
  2. Написать функцию main, которая:
    • Создаёт shopping cart
    • Добавляет в cart Laptop стоимостью $1200 и Headphones стоимостью $100
    • Создаёт BitcoinPayment с адресом кошелька "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    • Устанавливает эту payment strategy для cart
    • Вызывает метод checkout

Начальный код уже содержит if __name__ == "__main__": внизу. Вам не нужно добавлять его самостоятельно. Это соглашение Python, которое гарантирует, что ваша функция main() запускается только при непосредственном выполнении файла (а не при его импорте другим модулем). Просто определите функцию main(), и предоставленный блок вызовет её автоматически.

Следуйте той же структуре, что показана в примерах урока.

Попробуйте сами

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")

# Create your BitcoinPayment strategy class here


if __name__ == "__main__":
    main()
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Python