Поведенческие модели проектирования необходимы для оптимизации взаимодействия между объектами в программной системе. Один из таких паттернов, «Цепочка обязанностей», особенно полезен для организации и управления тем, как запрос обрабатывается различными компонентами системы. Отделяя отправителя запроса от его получателей, этот паттерн повышает гибкость и упрощает сопровождение кода. В этой статье мы рассмотрим паттерн «Цепочка обязанностей» и продемонстрируем его реализацию с помощью кода Swift.
Шаблон Цепочка обязанностей
Паттерн Цепочка обязанностей — это поведенческий паттерн проектирования, который позволяет обрабатывать запросы путем формирования цепочки объектов обработки. Каждый объект обработки содержит ссылку на следующий объект в цепочке. Согласно этому шаблону, при получении запроса каждый объект в цепочке либо обрабатывает запрос, либо передает его следующему объекту в цепочке. К основным преимуществам этого шаблона относятся:
- Разделение отправителя и получателя запроса.
- Динамическое добавление или изменение порядка обработки в цепочке.
- Повышение модульности и поддерживаемости кода.
Пример кода на Swift
Чтобы проиллюстрировать паттерн Цепочка обязанностей, рассмотрим простой пример: цепочку обработчиков, обрабатывающих запрос на снятие банкнот. Начнем с определения протокола для обработчиков:
protocol BanknoteHandler { var nextHandler: BanknoteHandler? { get set } func handle(withdrawalAmount: Int) -> Bool }
Далее мы создадим базовый класс для обработчиков, который реализует протокол BanknoteHandler:
class BaseBanknoteHandler: BanknoteHandler { var nextHandler: BanknoteHandler? func handle(withdrawalAmount: Int) -> Bool { return nextHandler?.handle(withdrawalAmount: withdrawalAmount) ?? false } }
Теперь мы создадим конкретные классы обработчиков для различных номиналов банкнот:
class HundredDollarHandler: BaseBanknoteHandler { override func handle(withdrawalAmount: Int) -> Bool { let remainingAmount = withdrawalAmount % 100 let numberOfBills = withdrawalAmount / 100 if numberOfBills > 0 { print("Dispensing \(numberOfBills) x $100 bills") } return nextHandler?.handle(withdrawalAmount: remainingAmount) ?? (remainingAmount == 0) } } class FiftyDollarHandler: BaseBanknoteHandler { override func handle(withdrawalAmount: Int) -> Bool { let remainingAmount = withdrawalAmount % 50 let numberOfBills = withdrawalAmount / 50 if numberOfBills > 0 { print("Dispensing \(numberOfBills) x $50 bills") } return nextHandler?.handle(withdrawalAmount: remainingAmount) ?? (remainingAmount == 0) } } // Additional handlers for $20, $10, and $5 bills can be created similarly.
Наконец, давайте создадим клиентский класс, который инициализирует цепочку обработчиков и обрабатывает запрос на снятие денег:
class ATM { private let hundredDollarHandler = HundredDollarHandler() private let fiftyDollarHandler = FiftyDollarHandler() // Initialize other handlers here. init() { hundredDollarHandler.nextHandler = fiftyDollarHandler // Set the next handler for each handler in the chain. } func withdraw(amount: Int) { guard amount % 5 == 0 else { print("Invalid withdrawal amount. Must be a multiple of 5.") return } print("Processing withdrawal of $\(amount)") hundredDollarHandler.handle(withdrawalAmount: amount) } } // Additional handlers for $20, $10, and $5 bills can be initialized and linked in the chain similarly.
Теперь, когда мы установили класс банкомата, мы можем создать его экземпляр и выполнить снятие денег:
let atm = ATM() atm.withdraw(amount: 365)
Это приведет к такому выводу:
Processing withdrawal of $365 Dispensing 3 x $100 bills Dispensing 1 x $50 bills Dispensing 1 x $10 bills Dispensing 1 x $5 bills
Как видно из примера, паттерн Цепочка обязанностей позволяет легко управлять запросом на снятие средств, отделяя отправителя (класс банкомата) от получателей (обработчиков банкнот). Каждый обработчик отвечает за обработку своей части запроса и передает оставшуюся сумму следующему обработчику в цепочке. Такая конструкция повышает модульность и поддерживаемость кода, изолируя обязанности каждого обработчика и позволяя динамически изменять цепочку обработки.
Заключение
Паттерн Цепочка обязанностей — это бесценный инструмент для организации обработки запросов и оптимизации взаимодействия между объектами в программной системе. Отделяя отправителя запроса от его получателей, этот шаблон способствует гибкости, модульности и удобству сопровождения кода. Пример кода на языке Swift, приведенный в этой статье, демонстрирует, как реализовать паттерн Цепочка обязанностей для запроса на снятие денег в банкомате, иллюстрируя полезность паттерна в реальных сценариях.