Гарно реалізовано, але, на жаль, це не реалізація стратегії в розумінні ООП. Ваша реалізація - це якийсь ізольований монотипний контейнер. Замість того, щоб бути носієм контексту(інкапсулювати одну конкретну реалізацію з можливістю заміни на іншу), ваш сервіс зберігає інстанси всіх реалізацій, про які взагалі не повинен знати, а контекст отримує в параметрі методу.
@@10xdev Саме так, тому що таким чином ми прив'язуємо момент вибору стратегії до моменту її реалізації, а це нівелює всі переваги патерну. В контексті пхп, я б фокусувався не на setStrategy(), а на конструктор, в який повинна приходити вже вибрана(!) стратегія.
> ми прив'язуємо момент вибору стратегії до моменту її реалізації, а це нівелює всі переваги патерну тут не дуже зрозумів що маєте на увазі, яким чином ми привʼязуємо? І ще маю кілька питань: 1. Як це має працювати в контексті сучасних фреймворків? Як ми можемо побудувати контейнер з правильною стратегією, якщо ми про неї дізнаємось лише в рантаймі? 2. А можете дати посилання на якісь ресурси де сказано про це обмеження? В мене GOF під руками нема, а у вікі таке > Typically, the strategy pattern stores a reference to code in a data structure and retrieves it. This can be achieved by mechanisms such as the native function pointer, the first-class function, classes or class instances in object-oriented programming languages, or accessing the language implementation's internal storage of code via reflection. en.wikipedia.org/wiki/Strategy_pattern тобто те, яким чином контекст знає про чи дістає стратегії не являється ключовим в паттерні. Ключове наступне: > In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives runtime instructions as to which in a family of algorithms to use.[1] > For instance, a class that performs validation on incoming data may use the strategy pattern to select a validation algorithm depending on the type of data, the source of the data, user choice, or other discriminating factors. These factors are not known until runtime and may require radically different validation to be performed. The validation algorithms (strategies), encapsulated separately from the validating object, may be used by other validating objects in different areas of the system (or even different systems) without code duplication. простими словами - суть в розділенні алгоритма від контекста з можливістю вибирати алгоритм в рантаймі Наперед дякую за конструктивну дискусію)
@@10xdev дякую за відповіді, тепер до дискусії. > ми прив'язуємо момент вибору стратегії до моменту її реалізації, Вибір стратегії - це коли ми, на основі контексту, вибираємо потрібний алгоритм. Реалізація стратегії - це виконання вибраного алгоритму. У вас ці два процеси відбуваються в одному методі, тим самим позбавляють клас контексту сенсу зберігати в собі вибрану стратегію, а це його пряма відповідальність. > Як це має працювати в контексті сучасних фреймворків? Як ми можемо побудувати контейнер з правильною стратегією, якщо ми про неї дізнаємось лише в рантаймі? Якщо у нас нема дефолтного алгоритму, тоді дійсно важко прикрутити стратегію до контейнера. Перше, що приходить на думку - білдер, який буде на виході видавати або стратегію з гарантованою наявністю в ній алгоритму, або Exception. > А можете дати посилання на якісь ресурси де сказано про це обмеження? У мене на жаль, теж нема під рукою GoF, але є ресурси, на які ви ж посилались. Взято з вашого посилання: a behavioral software design pattern that *enables* selecting an algorithm at runtime Тобто, "вмикає" вибір алгоритму в рантаймі, але безпосередньо не вибирає алгоритм. З того ж refactoring guru: The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy. ------------------- > тобто те, яким чином контекст знає про чи дістає стратегії не являється ключовим в паттерні якщо контекст знає про всі можливі стратегії, то це вже важко назвати контекстом. Ваш сервіс стає контекстом тільки на дуже короткий проміжок часу, коли вибирає і виконує вибрану стратегію. Після цього він знову перестає бути контекстом. > суть в розділенні алгоритма від контекста з можливістю вибирати алгоритм в рантаймі Все так, але навіщо вибирати алгоритм в контексті? Питання в тому, який код приймає рішення на основі існуючих даних, яку стратегію вибрати. Зараз цим займається ваш сервіс, відповідальність якого в ідеалі повинна закінчуватись на зберіганні вибраної стратегії і делегуванні їй роботи. Приймати рішення про вибрану стратегію - це завдання клієнтського коду, а не контексту. ------------------- Пропоную вам подумати над цілком реальною задачею. Уявімо, що ваша платформа розвивається дуже динамічно, ви додали ще один банк(ощад), мультимовність і створили мобільний додаток, який комунікує з бекендом через stateless REST API. Відповідно, побудова посилань теж ускладнилась. Потрібно розширити набір факторів вибору стратегії, відповідно, і набір стратегій. Монобанк має дві версії сайту і одну мову (+1 стратегія по критерію пристрою) Приват має одну версію сайту і дві мови (+1 стратегія по критерію мови) Ощад має одну версію сайту і одну мову(+1 стратегія) Коли юзер приходить із сайту, мова лежить у нього в сесії, а коли з мобільного додатку, в параметрі урла. Пристрій ми визначаємо по тому, який метод контролера обробляє запит. Цікаво, як би ви розширили існуючу архітектуру, маючи таке завдання. Можна просто описати кількома реченнями.
Вітаю! Давайте з кінця, з вашої задачі. 1. Додаємо по стратегії на кожен описаний вами кейс 2. Згідно з описом паттерну клієнти контексту передають контексту відповідну стратегію (в мому випадку імʼя стратегії). Грубо - в контролері, але швидш за все в окремому сервісі який має визначити стратегію для вказаних вище умов Тобто моя ідея в тому, щоб залишити ініціювання стратегій фреймворку і просто передавати назву. В мому прикладі доволі прості обʼєкти інтеграцій, але уявіть що там логери, бази даних, сервіси інтеграцій 3rd parties, шифрування, etc. Як би ви вирішили цю задачу? > У мене на жаль, теж нема під рукою GoF, але є ресурси, на які ви ж посилались. Взято з вашого посилання: a behavioral software design pattern that enables selecting an algorithm at runtime Тобто, "вмикає" вибір алгоритму в рантаймі, але безпосередньо не вибирає алгоритм. З того ж refactoring guru: The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy. так і у мене контекст не вибирає, йому клієнт каже яку стратегію виконати > Все так, але навіщо вибирати алгоритм в контексті? Питання в тому, який код приймає рішення на основі існуючих даних, яку стратегію вибрати. Зараз цим займається ваш сервіс, відповідальність якого в ідеалі повинна закінчуватись на зберіганні вибраної стратегії і делегуванні їй роботи. Приймати рішення про вибрану стратегію - це завдання клієнтського коду, а не контексту. знову ж таки - вибирає контролер на базі юзер інпуту, контекст не вибирає алгоритм Цікаво як би ви виконали цю задачу в умовах великої кількості алгоритмів, де в кожного багато можливих (різних!) залежностей. З того як розумію ваші слова - клієнтський код, відповідав би за створення стратегій. Відповідно він мав би ініціалізувати ці стратегії і знати про всі інтеграції і містити відповідні сервіси в себе. Дякую
О клас, давно шукала подібний контент
Дякую за відео
Якщо логіка визначення потрібної стратегії достатньо складна, чи має сенс використання фабрики стратегій?
Вітаю! Як саме це мало б виглядати? Звучить трохи складно (або не розумію ідею). Але сервіс, який визначить яку стратегію використати - цілком ок
Гарно реалізовано, але, на жаль, це не реалізація стратегії в розумінні ООП. Ваша реалізація - це якийсь ізольований монотипний контейнер. Замість того, щоб бути носієм контексту(інкапсулювати одну конкретну реалізацію з можливістю заміни на іншу), ваш сервіс зберігає інстанси всіх реалізацій, про які взагалі не повинен знати, а контекст отримує в параметрі методу.
дякую за комент!
Тобто якщо ми замість setStrategy(new Strategy()) просто кажемо яку стратегію використати, то це вже не буде стратегією?
@@10xdev Саме так, тому що таким чином ми прив'язуємо момент вибору стратегії до моменту її реалізації, а це нівелює всі переваги патерну. В контексті пхп, я б фокусувався не на setStrategy(), а на конструктор, в який повинна приходити вже вибрана(!) стратегія.
> ми прив'язуємо момент вибору стратегії до моменту її реалізації, а це нівелює всі переваги патерну
тут не дуже зрозумів що маєте на увазі, яким чином ми привʼязуємо?
І ще маю кілька питань:
1. Як це має працювати в контексті сучасних фреймворків? Як ми можемо побудувати контейнер з правильною стратегією, якщо ми про неї дізнаємось лише в рантаймі?
2. А можете дати посилання на якісь ресурси де сказано про це обмеження? В мене GOF під руками нема, а у вікі таке
> Typically, the strategy pattern stores a reference to code in a data structure and retrieves it. This can be achieved by mechanisms such as the native function pointer, the first-class function, classes or class instances in object-oriented programming languages, or accessing the language implementation's internal storage of code via reflection.
en.wikipedia.org/wiki/Strategy_pattern
тобто те, яким чином контекст знає про чи дістає стратегії не являється ключовим в паттерні. Ключове наступне:
> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives runtime instructions as to which in a family of algorithms to use.[1]
> For instance, a class that performs validation on incoming data may use the strategy pattern to select a validation algorithm depending on the type of data, the source of the data, user choice, or other discriminating factors. These factors are not known until runtime and may require radically different validation to be performed. The validation algorithms (strategies), encapsulated separately from the validating object, may be used by other validating objects in different areas of the system (or even different systems) without code duplication.
простими словами - суть в розділенні алгоритма від контекста з можливістю вибирати алгоритм в рантаймі
Наперед дякую за конструктивну дискусію)
@@10xdev дякую за відповіді, тепер до дискусії.
> ми прив'язуємо момент вибору стратегії до моменту її реалізації,
Вибір стратегії - це коли ми, на основі контексту, вибираємо потрібний алгоритм.
Реалізація стратегії - це виконання вибраного алгоритму.
У вас ці два процеси відбуваються в одному методі, тим самим позбавляють клас контексту сенсу зберігати в собі вибрану стратегію, а це його пряма відповідальність.
> Як це має працювати в контексті сучасних фреймворків? Як ми можемо побудувати контейнер з правильною стратегією, якщо ми про неї дізнаємось лише в рантаймі?
Якщо у нас нема дефолтного алгоритму, тоді дійсно важко прикрутити стратегію до контейнера. Перше, що приходить на думку - білдер, який буде на виході видавати або стратегію з гарантованою наявністю в ній алгоритму, або Exception.
> А можете дати посилання на якісь ресурси де сказано про це обмеження?
У мене на жаль, теж нема під рукою GoF, але є ресурси, на які ви ж посилались.
Взято з вашого посилання: a behavioral software design pattern that *enables* selecting an algorithm at runtime
Тобто, "вмикає" вибір алгоритму в рантаймі, але безпосередньо не вибирає алгоритм.
З того ж refactoring guru:
The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy.
-------------------
> тобто те, яким чином контекст знає про чи дістає стратегії не являється ключовим в паттерні
якщо контекст знає про всі можливі стратегії, то це вже важко назвати контекстом. Ваш сервіс стає контекстом тільки на дуже короткий проміжок часу, коли вибирає і виконує вибрану стратегію. Після цього він знову перестає бути контекстом.
> суть в розділенні алгоритма від контекста з можливістю вибирати алгоритм в рантаймі
Все так, але навіщо вибирати алгоритм в контексті?
Питання в тому, який код приймає рішення на основі існуючих даних, яку стратегію вибрати. Зараз цим займається ваш сервіс, відповідальність якого в ідеалі повинна закінчуватись на зберіганні вибраної стратегії і делегуванні їй роботи. Приймати рішення про вибрану стратегію - це завдання клієнтського коду, а не контексту.
-------------------
Пропоную вам подумати над цілком реальною задачею.
Уявімо, що ваша платформа розвивається дуже динамічно, ви додали ще один банк(ощад), мультимовність і створили мобільний додаток, який комунікує з бекендом через stateless REST API. Відповідно, побудова посилань теж ускладнилась. Потрібно розширити набір факторів вибору стратегії, відповідно, і набір стратегій.
Монобанк має дві версії сайту і одну мову (+1 стратегія по критерію пристрою)
Приват має одну версію сайту і дві мови (+1 стратегія по критерію мови)
Ощад має одну версію сайту і одну мову(+1 стратегія)
Коли юзер приходить із сайту, мова лежить у нього в сесії, а коли з мобільного додатку, в параметрі урла.
Пристрій ми визначаємо по тому, який метод контролера обробляє запит.
Цікаво, як би ви розширили існуючу архітектуру, маючи таке завдання. Можна просто описати кількома реченнями.
Вітаю!
Давайте з кінця, з вашої задачі.
1. Додаємо по стратегії на кожен описаний вами кейс
2. Згідно з описом паттерну клієнти контексту передають контексту відповідну стратегію (в мому випадку імʼя стратегії). Грубо - в контролері, але швидш за все в окремому сервісі який має визначити стратегію для вказаних вище умов
Тобто моя ідея в тому, щоб залишити ініціювання стратегій фреймворку і просто передавати назву. В мому прикладі доволі прості обʼєкти інтеграцій, але уявіть що там логери, бази даних, сервіси інтеграцій 3rd parties, шифрування, etc.
Як би ви вирішили цю задачу?
> У мене на жаль, теж нема під рукою GoF, але є ресурси, на які ви ж посилались.
Взято з вашого посилання: a behavioral software design pattern that enables selecting an algorithm at runtime
Тобто, "вмикає" вибір алгоритму в рантаймі, але безпосередньо не вибирає алгоритм.
З того ж refactoring guru:
The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn’t know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy.
так і у мене контекст не вибирає, йому клієнт каже яку стратегію виконати
> Все так, але навіщо вибирати алгоритм в контексті?
Питання в тому, який код приймає рішення на основі існуючих даних, яку стратегію вибрати. Зараз цим займається ваш сервіс, відповідальність якого в ідеалі повинна закінчуватись на зберіганні вибраної стратегії і делегуванні їй роботи. Приймати рішення про вибрану стратегію - це завдання клієнтського коду, а не контексту.
знову ж таки - вибирає контролер на базі юзер інпуту, контекст не вибирає алгоритм
Цікаво як би ви виконали цю задачу в умовах великої кількості алгоритмів, де в кожного багато можливих (різних!) залежностей. З того як розумію ваші слова - клієнтський код, відповідав би за створення стратегій. Відповідно він мав би ініціалізувати ці стратегії і знати про всі інтеграції і містити відповідні сервіси в себе.
Дякую