З одного боку, великі скупчення if/else
блоків не є легко перевірити . Кожна нова "гілка" додає ще один шлях виконання і тим самим збільшує циклічну складність . Якщо ви хочете ретельно протестувати свій код, вам доведеться охопити всі шляхи виконання, і кожна умова вимагатиме від вас написати принаймні ще один тест (якщо ви пишете невеликі, зосереджені тести). З іншого боку, класи, які реалізують стратегії, зазвичай піддають лише 1 публічний метод, який легко перевірити.
Отже, за допомогою вкладеної програми if/else
ви отримаєте багато тестів для однієї частини коду, тоді як зі стратегією у вас буде кілька тестів для кожної з декількох простіших стратегій. З останньою можливістю кращого покриття, оскільки складніше пропустити шляхи виконання.
Що стосується розширюваності , уявіть, що ви пишете рамки, де користувачі повинні мати можливість вводити власну поведінку. Наприклад, ви хочете створити якусь структуру податкових розрахунків і хочете підтримати податкові системи різних країн. Замість того, щоб реалізувати їх усі, ви просто хочете надати рамковим користувачам можливість реалізувати спосіб обчислення деяких конкретних податків.
Ось стратегія:
- Ви визначаєте інтерфейс, наприклад
TaxCalculation
, і ваша система приймає екземпляри такого типу для обчислення податків
- Користувач фреймворку створює клас, який реалізує цей інтерфейс і передає його вашому фреймворку, забезпечуючи таким чином спосіб виконати деяку частину обчислень
Ви не можете зробити те ж саме з if/else
тим, що це вимагало б змінити код фреймворку, і в цьому випадку це більше не буде рамкою. Оскільки рамки часто поширюються у складеному вигляді, це може бути єдиним варіантом.
Однак, навіть якщо ви просто пишете якийсь звичайний код, стратегія вигідна, оскільки робить ваші наміри яснішими. У ньому сказано, що "ця логіка є підключеною та умовною", тобто може бути кілька реалізацій, які можуть відрізнятися залежно від дій користувача, конфігурації чи навіть платформи.
Використання шаблону стратегії може покращити читабельність, оскільки, хоча клас, який реалізує якусь конкретну стратегію, зазвичай повинен мати описову назву, наприклад USAIncomeTaxCalculator
, if/else
блоки є "безіменними", у кращих випадках просто коментуються, а коментарі можуть лежати. Крім того, з мого особистого смаку, просто маючи більше 3 if/else
блоків поспіль не читабельно, і це стає погано з вкладеними блоками.
Принцип відкритого / закритого типу також є дуже актуальним, оскільки, як я описав у прикладі вище, стратегія дозволяє розширити логіку в деяких частинах коду ("відкрито для розширення"), не переписуючи ці частини ("закриті для модифікації" ).