Паттерн 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 позволяет переключать алгоритмы во время выполнения. Определите разные стратегии с одним и тем же интерфейсом, а затем позвольте классу контекста выбрать, какую из них использовать. Это делает ваш код гибким и позволяет легко расширять его новыми алгоритмами без изменения существующего кода.
Задание
СреднеРеализуйте новую стратегию BitcoinPayment для нашей системы shopping.
Ваша задача:
- Создать class BitcoinPayment, реализующий PaymentStrategy
- Он должен принимать wallet_address в конструкторе
- Метод pay должен выводить точно:
Paying $X using Bitcoin wallet: Y, где X — это сумма, а Y — адрес кошелька - Метод pay должен возвращать True после вывода сообщения
- Написать функцию 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()В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — Простой калькулятор4Наследование
Базовое наследованиеФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовИтоги — Иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy5Полиморфизм
Снова о переопределении методовУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовИтоги — Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыИтоги — Менеджер банковского счета6Инкапсуляция
Public, Protected, Private члены классаМодификаторы доступаСокрытие данныхДекораторы property: продвинутый уровеньИтоги: Система учета студентов12Проект: Управление библиотекой
Обзор проектаКлассы Book и UserСистема выдачи книгФункционал поискаИнтерфейс администратораТестирование и интеграцияПотренируйтесь самостоятельно: Онлайн-компилятор Python