30-50% off hundreds of digital assets! WordPress themes, video, music and more 30-50% Off Go to Sale
Advertisement
  1. Code
  2. Design Patterns
Code

Шаблони проектування: Стратегія (Strategy Pattern)

by
Difficulty:IntermediateLength:ShortLanguages:
This post is part of a series called Design Patterns in PHP.
Design Patterns: The Decorator Pattern
Design Patterns: The Simple Factory Pattern

Ukrainian (українська мова) translation by Anton Bagaiev (you can also view the original English article)

Шаблони проектування: Стратегія(Strategy Pattern)

В цій навчальній серії ми вже охопили три шаблони(або патерни) проектування. Також ми визначили чотири категорії для різних шаблонів проектування. В цій статті я розповім про шаблон стратегії(Strategy Pattern), що підпадає під категорію шаблонів поведінки(Behavioral Design Patterns)

У вас може виникнути питання: коли ми маємо застосовувати цей патерн? І я відповім, що ми маємо застосовувати стратегію, коли у нас є декілька шляхів(алгоритмів) для виконання однієї операції та ми хочемо, щоб програма обирала конкретний шлях відповідно до ваших потреб. Цей патерн також відомий, як патерн поведінки(policy pattern).

Найпростішим прикладом для цього може бути вибір методу сортування. Наприклад, ми маємо декілька алгоритмів сортування масивів, але, залежно від кількості елементів у масиві, ми маємо обрати той алгоритм, що забезпечить найкраще виконання.

Цей патерн також відомий, як патерн поведінки(policy pattern).

Проблема

Для прикладу я візьму інтернет-магазин, у який інтегровано декілька платіжних систем. Крім того, що сайт має декілька платіжних систем, відповідно до вимог, їх не потрібно виводити користувачеві одночасно. Але відповідна платіжна система має бути підключена на льоту, залежно від суми вартості товарів у кошику.

Використовуючи цей приклад, ми можемо визначити наступне: коли сума товарів у кошику менша за 500$, оплату необхідно проводити за допомогою стандарту PayPal, але коли сума є рівною або більша за 500$, нам необхідно використовувати збережені дані кредитної картки(припускаючи, що дані вже збережені).

Без застосування відповідної стратегії наш код буде виглядати так:

Для початку нам треба створити два окремі класи для оплати за допомогою PayPal та оплати за допомогою кредитної карти.

Також, ви можете зауважити, що нам необхідно додати умови, щоб змусити наш код працювати. Уявіть кількість змін, що ми маємо зробити, якщо нам знадобиться додати зміни у цю логіку, або ми знайдемо помилку, що також змусить нас змінювати код. Тоді нам доведеться патчити всі місця використання цього коду.

Рішення

Тепер ми виконаємо ці вимоги, але з використанням патерну стратегії, що дозволить нам зробити код більш прозорим, зрозумілим та розширюваним.

Інтерфейс

Для цього спочатку введемо інтерфейс, що буде реалізовувати кожен клас платіжної системи. Зрештою, додамо інтерфейси до наших стратегій.

Наступним кроком ми створимо основний клас(у структурі патерну він зазвичай вказується як Context), що зможе використовувати стратегії, які ми вже розробили.

Тут ми можемо побачити, що умови вибору потрібної платіжної системи загорнуті у метод payAmount(). Тепер давайте охопимо весь код і подивимось, як нам використовувати це надалі.

Ми можемо побачити, що вибір платіжної системи недоступний для нашої програми. Також, згідно вимог, ми маємо реалізацію всіх відповідних платіжних систем для проведення банківської транзакції.

Додаємо нову стратегію

Якщо пізніше нам знадобиться додати нову стратегію(в цьому прикладі - нову платіжну систему) з іншою логікою, це буде дуже легко зробити у нашому випадку. Скажімо, ми хочемо додати новую платіжну систему Moneybooker, і хочемо використовувати її, коли маємо вартість товарів у кошику більше за 500$, але менше за 1000$.

Все, що ми маємо зробити - це додати новий клас стратегії, що реалізує вищезазначений інтерфейс, і ми можемо просуватись далі.

Тепер ми маємо наш новий клас стратегії, і все, що нам залишилось змінити, це наш основний метод payAmount(). Він потребує таких змін:

Ви можете побачити, що ми зробили зміни лише в методі payAmount(), замість зміни коду, що викликає цей метод.

Отже

Ми можемо зробити висновок, що, маючи декілька шляхів виконання схожих завдань(в прикладному програмуванні радше говорити - коли ми маємо декілька алгоритмів для виконання однієї операції), ми маємо прибігати до використання шаблону стратегії.

Використовуючи цей патерн, нам легко додавати чи видаляти алгоритми, тому що зміна цих алгоритмів недоступна основній програмі.

Я спробував максимально зрозуміло використати простий, але практичний приклад для демонстрації шаблону стратегії, тож, якщо у вас залишились коментарі чи питання, не соромтесь задавати їх у коментарях до статті.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.