Эти "люди" в лице полутора местных землекопов, очевидно, не умеют готовить ООП.
ООП, как и любая парадигма, действительно требует мыслить в её рамках. Без этого - непонимание и отторжение
если моделируют бизнес требования через FSM, что приводит к комбинаторному взрыву при попытке реализовать все реальные варианты переходов.
FSM очень мощный инструмент, позволяющий решить задачу организации сложного взаимодействия, но да, это не серебряная пуля, не стоит её применять везде, где ни попадя.
А вот люди, которые профессионально за деньги писали код на дельфи, плюсах, джаве, хаскеле, руби, джаваскрипте, эрланге, эликсире (и еще некоторых других языках мимоходом) — вам говорят, что нет, не выглядит удачным, в сравнении с другими парадигмами.
Ну если люди говорят, тогда да. Не ожидал именно от Вас услышать такой аргумент
А в реальной жизни в энтерпрайзе — код разбухает в геометрической прогрессии и начинается программирование абстракций ради абстракций, чтобы заткнуть дыры применимости.
Чёт в реальном энтерпрайзе, если и есть некоторое количество систем на Haskell, то чисто следовое. Все мучаются с ООП.
Вон даже FSM с гарантиями не построить, как мы видим по примерам выше.
Какие гарантии должны быть у FSM? Отсутствие тупиковых/недостижимых стейтов? Не надо решать несуществующую проблему
Подождите, я не понимаю. Как вы разделяете, что идёт в enter «следующего» состояния, а что — в exit «предыдущего»?
Кроме переопределения реакции на внешние стимулы, у каждого стейта есть возможность переопределить действия по переходу в этот стейт и выходу из него вне зависимости от стейта, куда идёт переход (Полезно для управления стейто-контекстными счётчиками итп). В общем случае есть ещё и набор действий, осуществляемых при переходе между конкретными стейтами.
Вот у меня есть, опять же, пусть простой случай — заказ в состоянии Finalized. При переходе в состояние Paid надо проверить, что платёжные реквизиты норм, и выслать письмо покупателю. Что тут куда идёт?
Вызываем у FSM соответствующий метод. FSM вызывает аналогичный у текущего стейта. Если логика предметной части (проверка реквизитов) прошла - стейт инициирует переход в Paid. если не прошла - в Error
Кто такой fsm? Это какой-то класс-менеджер? Инстанс конкретной стейтмашины, построенной по данным бизнес-правилам?
Это инстанс конкретной fsm, с которым собственно и осуществляется взаимодействие. Стейты - приватные классы и видны исключительно внутри fsm
И когда нам захотелось перед done воткнуть стейт saving, придется поменять все классы, которые умели переходить в done, так?
Когда нам захотелось добавить новый стейт, мы:
наследуем его, переопределяем, если надо для него enter() и exit() - то что будет обрабатываться при переходе в стейт и покидании его.
дополняем fsm методом gotoSaving()
реализуем логику перехода в новый стейт, там, где это надо по задаче. Например, в некоторых местах где gotoDone() теперь будет gotoSaving()
Всё. З.Ы. Мне кажется, что наша беседа имеет некоторый привкус вкусовщины. Безусловно, на любом языке можно реализовать что угодно, и на вкус и цвет все фломастеры ... Предлагаю сойтись на тезисе, что FSM решает множество проблем и их применение в подавляющем большинстве случаев оправдано. Отдельно хочу отметить необходимость следования парадигме языка, который используется.
Человек прекрасно использует fsm с ООП, не беспокойтесь. Просто представьте, что поведение fsm определяется методами стейтов, которые за счёт полиморфизма наследования меняют свою реакцию на евенты. Никакого прямого изменения стейтов нет. Состояние скрыто. Конструкция банальна.
И здравствуй проверка в каждом из этих методов, которую надо не забыть поменять, когда добавилось новое состояние.
И никакого здравствуй. Новое состояние описывает только реакцию объекта, которое fsm в этом состоянии осуществляет. Напоминаю, что стейты наследуются - у нас же ООП и силами полиморфизма определяется поведение fsm в данном стейте
Ну значит, вам придется защищаться от рефлексии, от аспектов, а еще нарисовать не поддающегося никакому когнитивному анализу макаронного монстра в setStatus.
Ничего из перечисленного мне не встречалось. А вместо setStatus(Status newStatus_) вполне уместны условные setError(), setIdle() и подобные. (Это если совсем примитивизировать - а на практике ещё и наборы для enter, exit определённые у классов иерархии state и transit у самой fsm) Уж чего чего, а Его Макаронность, ООП как раз отлично структурирует в отличие от
Мой опыт подсказывает, что если вы думаете, то вам нужен конечный автомат, то скорее всего вам не нужен конечный автомат.
Мой опыт подсказывает обратное - везде где встречается сколь угодно отличная от нуля сложность - конечный автомат или их композиция делает систему прогнозируемой и отлаживаемой
Иначе это просто поле status из базы, которое может поменять как угодно кто угодно.
Хорошо, пусть будет status (правда не пойму причём здесь база). И как кто угодно собирается поменять его значение, если оно private? Инкапсуляцию никто не отменял
Может я чего-то и упустил, но тогда Вы говорите о состоянии заказа а не о самом заказе. ООП как раз исходит из сокрытия состояния.
Order1 = pay(Order)
и в функции pay() мы скопируем всё, начиная с австро-прусской войны, включая состав заказа, плательщика-получателя, менеджеров, которые его ведут и прочие погоды на Марсе, важные для прикладной задачи.
Обычно это делают с помощью конечных автоматов.
fsm и ООП никоим образом не противоречат друг другу, а наоборот, очень гармонично взаимно дополняют. А что с хранением истории заказа?
Потому что новый заказ и оплаченный заказ — это две абсолютно разные сущности
Ага, как и ЧастичноОплаченныйЧастичноСобранныйЧастичноОтгруженныйЧастичноВозвращённыйЧастичноОтменённыйИтпИтд заказ. Статус оплаты - один из атрибутов заказа, коих может быть очень много в реальной системе. Сколько видов сущностей надо завести под все возможные сочетания состояний заказа? Как установить между ними всеми связи?
Так вроде снижение ментальной нагрузки - это как раз плюс. Вон у brainfuck ментальная нагрузка о-го-го какая, но чёт на нём никто особо крупных систем не замечено ))
Можно было бы также обсудить и сам вызов методов через точку, появившийся еще в Smalltalk в 1970-ых годах, откуда он и перекочевал в большинство современных языков.
В Smalltalk никакого вызова метода через точку нет.
ООП, как и любая парадигма, действительно требует мыслить в её рамках. Без этого - непонимание и отторжение
FSM очень мощный инструмент, позволяющий решить задачу организации сложного взаимодействия, но да, это не серебряная пуля, не стоит её применять везде, где ни попадя.
Ну если люди говорят, тогда да. Не ожидал именно от Вас услышать такой аргумент
Чёт в реальном энтерпрайзе, если и есть некоторое количество систем на Haskell, то чисто следовое. Все мучаются с ООП.
Какие гарантии должны быть у FSM? Отсутствие тупиковых/недостижимых стейтов? Не надо решать несуществующую проблему
Сам концепт ООП нужен для инкапсулирования сложности. Вероятно, есть и другие методы, но ООП выглядит вполне удачным
Кроме переопределения реакции на внешние стимулы, у каждого стейта есть возможность переопределить действия по переходу в этот стейт и выходу из него вне зависимости от стейта, куда идёт переход (Полезно для управления стейто-контекстными счётчиками итп). В общем случае есть ещё и набор действий, осуществляемых при переходе между конкретными стейтами.
Вызываем у FSM соответствующий метод. FSM вызывает аналогичный у текущего стейта. Если логика предметной части (проверка реквизитов) прошла - стейт инициирует переход в Paid. если не прошла - в Error
Это инстанс конкретной fsm, с которым собственно и осуществляется взаимодействие. Стейты - приватные классы и видны исключительно внутри fsm
Когда нам захотелось добавить новый стейт, мы:
наследуем его, переопределяем, если надо для него enter() и exit() - то что будет обрабатываться при переходе в стейт и покидании его.
дополняем fsm методом gotoSaving()
реализуем логику перехода в новый стейт, там, где это надо по задаче. Например, в некоторых местах где gotoDone() теперь будет gotoSaving()
Всё.
З.Ы. Мне кажется, что наша беседа имеет некоторый привкус вкусовщины. Безусловно, на любом языке можно реализовать что угодно, и на вкус и цвет все фломастеры ...
Предлагаю сойтись на тезисе, что FSM решает множество проблем и их применение в подавляющем большинстве случаев оправдано. Отдельно хочу отметить необходимость следования парадигме языка, который используется.
Именно так. Мы же хотим переопределять поведение в зависимости от стейта. Фактически заводим объекту FSM вторую VTable
Человек прекрасно использует fsm с ООП, не беспокойтесь. Просто представьте, что поведение fsm определяется методами стейтов, которые за счёт полиморфизма наследования меняют свою реакцию на евенты. Никакого прямого изменения стейтов нет. Состояние скрыто. Конструкция банальна.
Я не знаю haskell и поэтому не приведу Вам аналогичный пример. Но да, очевидно можно, если приведённый код делает что-либо осмысленное
И никакого здравствуй. Новое состояние описывает только реакцию объекта, которое fsm в этом состоянии осуществляет.
Напоминаю, что стейты наследуются - у нас же ООП и силами полиморфизма определяется поведение fsm в данном стейте
Ничего из перечисленного мне не встречалось. А вместо setStatus(Status newStatus_) вполне уместны условные setError(), setIdle() и подобные. (Это если совсем примитивизировать - а на практике ещё и наборы для enter, exit определённые у классов иерархии state и transit у самой fsm)
Уж чего чего, а Его Макаронность, ООП как раз отлично структурирует в отличие от
Мой опыт подсказывает обратное - везде где встречается сколь угодно отличная от нуля сложность - конечный автомат или их композиция делает систему прогнозируемой и отлаживаемой
Хорошо, пусть будет status (правда не пойму причём здесь база). И как кто угодно собирается поменять его значение, если оно private? Инкапсуляцию никто не отменял
Реализовывал и реализовываю. Подвоха не заметил. Поясните плз, может я чёго-то упускаю?
Может я чего-то и упустил, но тогда Вы говорите о состоянии заказа а не о самом заказе. ООП как раз исходит из сокрытия состояния.
и в функции pay() мы скопируем всё, начиная с австро-прусской войны, включая состав заказа, плательщика-получателя, менеджеров, которые его ведут и прочие погоды на Марсе, важные для прикладной задачи.
fsm и ООП никоим образом не противоречат друг другу, а наоборот, очень гармонично взаимно дополняют. А что с хранением истории заказа?
Ага, как и ЧастичноОплаченныйЧастичноСобранныйЧастичноОтгруженныйЧастичноВозвращённыйЧастичноОтменённыйИтпИтд заказ.
Статус оплаты - один из атрибутов заказа, коих может быть очень много в реальной системе.
Сколько видов сущностей надо завести под все возможные сочетания состояний заказа? Как установить между ними всеми связи?
Так вроде снижение ментальной нагрузки - это как раз плюс. Вон у brainfuck ментальная нагрузка о-го-го какая, но чёт на нём
никтоособо крупных систем не замечено ))А кто ж тогда живёт в methodDictionary ? ))
В Smalltalk никакого вызова метода через точку нет.
Как это Smalltalk без наследования? Там всё на этом построено!
Могу только посоветовать а
ффвтору ознакомиться с "Серебряной пули нет" Брукса