Конечный автомат: плохой дизайн? - PullRequest
8 голосов
/ 02 февраля 2010

Конечные автоматы вообще считаются плохим дизайном в ООП?

Я часто это слышу.И после того, как мне пришлось работать над действительно старой, недокументированной частью C ++, использующей его, я склонен согласиться.Отладка была трудной.

А как насчет проблем с читаемостью / ремонтопригодностью?

Ответы [ 7 ]

19 голосов
/ 02 февраля 2010

ФСМ никогда не следует считать плохими.Они слишком полезны, но люди, которые к ним не привыкли, часто считают их обременительными.

Существует множество способов реализовать один с ООП.Некоторые уродливее других.Ваши низкоуровневые парни будут использовать операторы switch, таблицы переходов или даже «goto».

Если вы ищете более чистый способ сделать это, я бы порекомендовал Boost's State Chart library , который построен только для реализации диаграмм состояний UML в C ++.Он использует современные методы шаблонов, чтобы сделать вещи более читабельными.Он также очень хорошо работает.

7 голосов
/ 02 февраля 2010

Конечные автоматы - это инструмент для достижения определенной цели. Как и любой инструмент, ими тоже можно злоупотреблять.

Они не самый добрый из инструментов, но работу, в которой они хороши, невозможно выполнить другими средствами (и обычно любой другой подход обречен быть ужасным беспорядком в тысячу раз хуже, чем машина).

Работа выполняется в условиях, когда классические состояния ожидания запрещены.

Я должен прочитать сенсорный экран. Чтобы прочитать позицию, мне нужно обменяться примерно 15 командами через SPI. Мне нужны хорошие 100 показаний в секунду. Мне нужно подождать около 1 микросекунды после каждой команды, чтобы соответствующий флаг занятости исчез, прежде чем я смогу продолжить. Существует также ряд других операций, которые должны быть доступны через тот же интерфейс, таких как настройка контрастности, изменение режимов, включение или выключение подсветки, считывание температуры. Если бы я выполнял while(BUSY_BIT); за каждое ожидание, я бы съел весь процессор за считанные минуты. Если бы я сделал sched_yield() или usleep(1), я бы никогда не достиг желаемого количества показаний. Единственный путь - это конечный автомат.

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

До сих пор в моем опыте работы преобладали 2 системы, основанные на 3 разных конечных автоматах.

  1. большой веб-портал, где на каждом шаге вы извлекаете некоторые данные из базы данных и на ее основе готовите больше запросов. На последнем шаге вы используете данные для генерации HTML. Каждая задача - модуль веб-страницы - была реализована как класс PHP, унаследованный от движка. Состояние было сохранено в переменных класса. Каждый шаг был отдельной функцией. В конце шага хранимые запросы были оптимизированы и отправлены в механизм через кэши, а ответы были возвращены к оригиналу.
  2. встроенное устройство со многими подсистемами. Task Pump используется. Каждый модуль регистрирует обработчик, который вызывается много раз в секунду из основного цикла. Обработчик может сохранять состояние в статических или классовых переменных с состояниями. Эта совместная многозадачность позволяет значительно уменьшить объем занимаемой памяти, чем запуск всех в отдельных потоках, позволяет вручную назначать приоритеты задачам, регистрируя их дважды, и запускать поток с высоким приоритетом, перекрывая остальную часть системы.
  3. пол-переводчик. Этот сенсорный экран. Вызовы функций и их состояния ожидания регистрируются, но каждый из них вызывается только один раз, а затем удаляется из очереди программы. Интерпретатор вызывается как задача taskpump, выполняющего ограниченное количество функций до тех пор, пока не встретит функцию, помеченную как состояние ожидания (или превышающую количество вызываемых функций). Затем оно продолжается, пока состояние ожидания не исчезнет. Другие задачи ставят в очередь задания как (иногда длинные) последовательности выполняемых функций, а затем ждут результата. Таким образом, я могу ограничить количество состояний, которые мне нужно создать, до 4, где мне нужны результаты. Если команда «отправить, никогда не проверять результат», например «установить контраст», им вообще не нужны дискретные состояния. Таким образом, фактическими состояниями являются «ожидание события и регистрация запрошенных данных», «ожидание измерения» и «считывание результатов и их правильное назначение».

Код будет в два раза проще и в три раза яснее, если будет написан структурно или последовательно. За исключением того, что это не будет работать, или будет работать с ужасной производительностью.

5 голосов
/ 02 февраля 2010

Не могу сказать вам, что Они говорят.

Но OO и FSM сортируют разные проблемные области. В области, где объекты взаимодействуют - это требует объектно-ориентированного подхода. В домене, где мир находится в том или ином государстве, - это требует разработки FSM.

Реально, вы можете смешивать эти проекты с / на разных уровнях абстракции, которые получатся более чистыми, чем использование только одного или другого.

2 голосов
/ 02 февраля 2010

Я бы сказал, что конечные автоматы гораздо легче отлаживать, чем другие способы решения тех же проблем (таких, как сопоставление с обычными языками).Что хорошо в FSM, так это все в имени ... у вас может быть конечный автомат с 15 состояниями, поэтому вы можете нарисовать диаграмму на листе бумаги, показывающую все переходы.Вы можете использовать диаграмму, чтобы выяснить полезные свойства системы, например, какие строки она принимает и как она попадает в состояние ошибки.В более сложных системах построение диаграмм часто бывает затруднено или невозможно.

Даже люди, которые говорят, что "gotos is evil", думают, что они являются правильным способом реализации конечных автоматов.(Конечно, некоторые люди думают, что gotos всегда злые ... но вы не можете угодить всем).

1 голос
/ 26 мая 2013

FSM можно легко понять и поддерживать, если код структурирован правильно. Я реализовал FSM в предыдущих работах, вот шаблон скелета:

FSM

1 голос
/ 02 февраля 2010

Я думаю, что если код хорошо документирован, нет проблем с его реализацией с использованием ООП-подхода. Большая часть C / C ++ используется для реализации FSM с использованием операторов switch, которые иногда могут ухудшить читабельность, если машина большая.

Недавно мне нужно было проанализировать обычный язык и внедрить FSM с использованием подхода ООП, удобочитаемость кода и удобство сопровождения были хорошими. Я имею в виду, гораздо лучше, чем использовать большие операторы switch.

Подсказка: в первый момент я реализовал состояния связи FSM и состояния, содержащие переходы. Тем не менее, в моем случае было бы лучше использовать класс для представления автомата, содержащий одну коллекцию состояний и другую из переходов. Мне стало проще клонировать машины (это было требованием для меня) и иметь меньшую функцию перехода.

Надеюсь, это поможет, Карлос.

0 голосов
/ 22 сентября 2011

Конечный автомат может использоваться для представления поведения любого класса.Если порядок входящих событий не имеет значения для поведения класса (комбинаторный класс), использование модели состояния не дает особого преимущества.

Однако, если поведение класса зависит от порядка входящих событий (последовательный класс)) State Machine представляет собой лучший выбор для анализа и реализации поведения.

Если вас интересует удобочитаемость / ремонтопригодность, используйте графические представления.Примеры поведения Классов, принадлежащих различным инженерным областям, представлены в графической и исполняемой форме по адресу http://www.StateSoft.org -> State Machine Gallery.

-Janusz

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...