Menu
Coddy logo textTech

Паттерн Strategy

Часть раздела Object Oriented Programming путешествия по 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]

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

challenge icon

Задание

Средне

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

Ваша задача:

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

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

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

Шпаргалка

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

Создайте классы стратегий с одинаковым интерфейсом:

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"

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

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)

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

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Проверьте себя

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

Все уроки раздела Object Oriented Programming