Menu
CoddyTech

Паттерн «Стратегия»

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

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

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

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)

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

Используй шаблон стратегии:

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]

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

challenge icon

Задание

Средне

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

Ваша задача:

  1. Создать класс BitcoinPayment, реализующий PaymentStrategy
    • Он должен принимать wallet_address в конструкторе
    • Метод pay должен вывести в точности: Paying $X using Bitcoin wallet: Y, где X — сумма, а Y — адрес кошелька
    • После вывода метод pay должен вернуть True
  2. Написать функцию main, которая:
    • Создаёт корзину покупок
    • Добавляет в корзину ноутбук стоимостью $1200 и наушники стоимостью $100
    • Создаёт BitcoinPayment с адресом кошелька "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    • Устанавливает эту стратегию оплаты для корзины
    • Вызывает метод 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")

# Создайте здесь класс стратегии BitcoinPayment


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

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

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

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