Как правильно использовать шаблон состояния? - PullRequest
41 голосов
/ 08 февраля 2011

Я встречал несколько реализаций шаблона состояний в своем опыте программирования и сделал несколько. Я видел, как они используются в различных сценариях (в основном пользовательский интерфейс и анализ). Беда в том, что все они под давлением быстрой разработки превратились в трудно поддерживаемые и понятные куски кода. Я подумываю о рефакторинге одного из них, но мне трудно найти хорошие ресурсы для этого в Интернете. Есть много простых примеров State Pattern онлайн, но мне нужны более глубокие ресурсы.

Итак, я ищу:

  • Примеры распространенных ошибок при реализация состояния модели и как избегай их,
  • Примеры из реального мира шаблон состояния выполнен правильно (как в какой-то проект с открытым исходным кодом / фреймворк)
  • Личный опыт с государством картина также приветствуется

Спасибо, что уделили время

Ответы [ 8 ]

25 голосов
/ 08 марта 2011

@ Иван: В Интернете доступно несколько ресурсов для Иерархические конечные автоматы (HSM). Миро Самек много писал об этом шаблоне проектирования и предлагает много полезной информации.

Некоторые статьи, которые должны представлять интерес:

Большим преимуществом использования HSM перед плоскими диаграммами состояний FSM, описанными Мили и Муром, является то, что иерархия создает разделение ответственности. Подсостояния должны обрабатывать только те условия, которые они специально предназначены для обработки - необработанные события передаются в родительское состояние, если родительское состояние явно не предназначено для его обработки, то оно передается следующему-более высокому родитель и тд. Это позволяет создавать небольшие управляемые конечные автоматы, каждый из которых служит одной цели - тот, который может вписаться в один объект. По мере добавления новых функций или добавления новых классов им нужно обрабатывать только свою маленькую часть мира и передавать необработанные события своим родителям.

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

24 голосов
/ 17 февраля 2011

Как вы, вероятно, прочитали, Шаблон проектирования состояний полезен, когда состояние изменяет поведение некоторого объекта, состав которого включает это состояние.Это подразумевает идею State абстрактного класса, интерфейса или перечислимого типа - хотя в зависимости от языка Duck Typing также подойдет - который определяет любое общее поведение и / илинеобходимые методы.

Ключевые аспекты

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

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

Примеры

Есть несколько сценариев, над которыми я либо работал, либо обсуждал, где это средство использования:

  1. Рабочий процесс
  2. Компьютерная играAI оппонента
  3. Оркестровка процесса

Под рабочий процесс Я имею в виду что-то вроде jBPM .Системы, подобные этой, направлены на то, чтобы отдавать должное внимание нужным людям в нужное время.Они обычно отправляют много писем или каких-либо других уведомлений.И процесс, который они представляют, нуждается в способности меняться по мере изменения организации, тогда как управляемые данные обычно меняются гораздо медленнее.

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

Process Orchestration похож на рабочий процесс, но сосредоточен на системной интеграции, а не на взаимодействии с людьми.Примером является Apache Mule framework.Здесь состояние может описывать состояние (например, запущен, в процессе, закончен) и тип (например, точка интеграции ftp, точка интеграции sql).

Заключение

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

8 голосов
/ 08 февраля 2011

Только мои 2 цента, шаблон состояния всегда трудно поддерживать, поскольку его трудно понять тем, кто его не кодировал. Я обычно возвращаюсь к старому стандартному массиву указателей функций / методов, как в моем старом опыте C. Вы просто строите двухмерный массив указателей на функции с состоянием / сигналом для строк / столбцов. Проще понять. у вас есть класс, который управляет этим, и вы делегируете другому классу для обработки сложности ...

my2c

6 голосов
/ 10 февраля 2011

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

Если у какого-либо штата есть какой-либо выбор, он в основном обрабатывает более одного состояния.

Мне нужна большая дисциплина, чтобы поддерживать состояния в чистоте.

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

4 голосов
/ 11 февраля 2011

взгляните на Конечный автомат . Почти у каждого зрелого языка есть свои хорошие примеры. Поскольку вы не указали предпочитаемый язык, я приведу пример C ++: Boost FSM library Скорее всего, это гораздо сложнее, чем нужно, но он может дать вам некоторые советы по дизайну наверняка

2 голосов
/ 12 ноября 2015

Итак, я ищу:

  • Примеры распространенных ошибок при реализации шаблона состояния и как их избежать,

Состояниешаблон не хорошо масштабируется.Представьте себе конечный автомат с 10 состояниями и 10 различными типами переходов.Добавление нового состояния означает, что это состояние должно определять все 10 переходов.Добавление нового перехода означает, что все 10 состояний должны его определить.Короче говоря, не используйте шаблон состояний, если ваш конечный автомат не стабилен и / или у вас много состояний / переходов.

  • Реальные примеры шаблонов состояний выполнены правильно(как в некоторых проектах / рамках с открытым исходным кодом)

Определите правильно :-) Пример Java, приведенный в https://stackoverflow.com/a/2707195/1168342, предназначен для жизненного цикла JSF, ноЯ думаю, что есть только один переход.Ни один из других ответов не приводит ничего для государства.

  • Также приветствуется личный опыт с шаблоном состояния

В Head First Design Patterns используется пример машины Гамбола для иллюстрации состояния,Это иронично, но каждый раз, когда они расширяют дизайн (добавляя новое состояние или переход), появляется много повторяющегося кода (особенно для недопустимых переходов в определенных состояниях).Кроме того, в зависимости от того, кто решает, каким будет следующее состояние, отдельные классы состояний могут быть связаны друг с другом (зависимости между состояниями).См. Объяснение в конце этого ответа: https://stackoverflow.com/a/30424503/1168342.

В книге GoF упоминается, что альтернативы на основе таблиц имеют преимущества, а именно их регулярность.Изменение критериев перехода требует изменения таблицы (а не кода).

1 голос
/ 17 февраля 2011

Вы должны использовать шаблон состояний, если у вас другое поведение для каждого состояния.Может быть, вам нужно перенастроить переходы во время выполнения.Еще одна причина для его использования - вам, возможно, придется добавить больше состояний позже.

Представьте себе настольную игру, например «Китайские шашки», у вас есть разные состояния графического интерфейса для выбора пешки, выберите целевой слот и так далее.В каждом состоянии графический интерфейс должен вести себя по-разному, некоторые входы должны обрабатываться, другие игнорироваться.Возможно использование простого переключателя / регистра, но шаблон состояний удобен, так как логика инкапсулирована, связанный код вместе.Это облегчает введение новых состояний, не затрагивая большинство / все остальные состояния (в зависимости от того, кто отвечает за установку переходов: либо состояние знает свои исходящие переходы, либо они могут быть заданы во время выполнения, например, с помощью конструктора).

Как видно из этого примера , GuiController использует интерфейс IGuiState для изменения своего поведения по требованию.Реализацию можно увидеть здесь .

Основной ловушкой является использование switch / case, когда вам нужно проявить гибкость.Поскольку перенаправление занимает немного больше времени, я бы рекомендовал это для фиксированного количества довольно простых состояний.Если вам нужно реализовать довольно быстрый сетевой протокол низкого уровня, который обычно требует больших затрат.

0 голосов
/ 24 октября 2015

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

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