Проблема проектирования шаблона с участием N состояний и переходов между ними
У меня проблема, и я не понимаю, какой шаблон дизайна использовать.
Проблема такова:
Мне нужно создать систему с состояниями "N", и моя система должна перейти от любого состояния к любому другому состоянию в зависимости от некоторых условий.
Пример:
При условии 1, перемещение из состояния 1 в 3 и условие 2 из состояния 1 в 4.
Даже переход из одного состояния в другое состояние может выполняться в двух или более разных условиях.
Например, переход из состояния 1 в состояние 3 можно выполнить, когда:
условие 1: "Его воскресенье"
условие 2: "Его дождь"
условие 3: "Его дождь и воскресенье"
В каждом условии обработка в состоянии 3 может быть разной.
Надеюсь, я смог понять проблему разборчиво. Просьба помочь.
Спасибо большое
Ответы
Ответ 1
Очевидно, что это случай конечной машины, но лучше сочетать условия, а не создавать новое условие для каждой комбинации. Мне не понравился пример Java для шаблона State в Википедии, поскольку государства знают о других состояниях, которые не имеют смысла во многих сценариях. Таблица перехода, которая отслеживает состояние состояния, применимые условия (состояния) и состояние, помогает решить эту проблему.
Мои два цента для объектно-ориентированной конечной машины. Есть улучшения, которые вы могли бы сделать на лицевой стороне OO, но это дает идею.
class Transition {
State from;
Set<Condition> conditions;
State to;
}
class State {
String state;
}
class Condition {
String condition;
}
Конечный автомат может быть построен с указанными выше типами. Проверка ошибок отсутствует, но вы можете сделать исключение или что-то еще, если для некоторых условий не найдено следующего состояния.
class StateMachine {
List<Transition> transitions;
State current;
StateMachine(State start, List<Transition> transitions) {
this.current = start;
this.transitions = transitions;
}
void apply(Set<Condition> conditions) {
current = getNextState(conditions);
}
State getNextState(Set<Condition> conditions) {
for(Transition transition : transitions) {
boolean currentStateMatches = transition.from.equals(current);
boolean conditionsMatch = transition.conditions.equals(conditions);
if(currentStateMatches && conditionsMatch) {
return transition.to;
}
}
return null;
}
}
И тестовый прогон:
Изменить. С некоторыми другими переходами и новыми состояниями на основе вашего комментария:
State one = new State("one");
State two = new State("two");
State three = new State("three");
Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");
List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);
StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three
У меня был горький опыт использования конечного автомата для довольно большого проекта. Проблема заключалась в составных состояниях. Точно так же, как составное условие, которое вы упомянули (воскресенье и дождь), может быть технически составным состоянием, которое может быть далее разбито на единичные состояния. Это может быть или не быть в вашей ситуации, но все же стоит упомянуть. Если это так, лучше всего изменить классическую машину конечного состояния и использовать набор состояний вместо одного состояния для представления состояний from и to. Если ваш N большой, это поможет сохранить уровень здравомыслия. Подумайте о папках hotmail и тегах gmail. Затем таблица перехода будет представлена как
Transition(Set<State> from, Set<Condition> conditions, Set<State> to)
Ответ 2
Это звучит как типичное использование для конечного автомата
Короче говоря, машина состояний описывает различные состояния, в которых может быть ваша система, и при каких условиях она может перейти из состояния в состояние. Конечный автомат описывается точно как ваше описание на английском языке. И его можно формально описать, используя диаграммы состояний
в коде вы можете сделать конечный автомат следующим образом:
enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
State state = State.Init;
while (state != State.Exit)
{
switch(state)
{
case State.Init:
init();
state = State.ShowMenu;
break;
case State.ShowMenu:
if(lastMenuItemSelected==1) state = State.ShowMsg;
if(lastMenuItemSelected==2) state = State.DisplayVideo;
break;
case State.ShowMsg:
....
break;
....
}
Я не уверен, правильно ли я получил правильный синтаксис для Java... Я больше в С#
Ответ 3
не будет работать шаблон состояния?
Ответ 4
Первое, что я заметил в вашем примере, это State 3 = (State 1 == true && State 2 == true). Это не будет очень хорошо масштабироваться по мере того, как будут задействованы более возможные состояния. Если вы только рассматриваете, идет ли дождь или воскресенье, вы можете иметь такое перечисление с 4-мя возможными типами:
enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }
Это позволит вам четко сформулировать условия в блоке коммутатора, когда пришло время кода. Но если вам нужно также подумать о том, тепло на улице, вам нужно добавить еще 4 значения для этого перечисления, чтобы зафиксировать все возможные условия. И позже в вашем проекте ваш код может потребовать захвата большего количества условий, чем вы в настоящее время видите.
Что касается шаблона проектирования, то образец состояния и его пример Java в Википедии выглядят как хорошее место для начала.
Пример Википедии имеет класс StateContext
с методом setState
, который принимает имя. Я думал о том, что вы добавили логику определения состояния здесь, но это сделало бы ваш класс StateContext
слишком близко к деталям реализации ваших других классов. Было бы лучше поставить метод определения состояния системы в классе, который бы легко знал условия перехода из одного состояния в другое. Таким образом, если ваш проект должен измениться в будущем, и у вас будет больше состояний для отслеживания или разных условий, вам нужно только поддерживать логику в одном месте.
Ответ 5
Как говорили другие, машина состояния может быть смоделирована в процедурный код с помощью переключателя или кода OO с шаблоном состояния, что, вероятно, было тем, что вы были после.
Однако третий способ состоит в том, чтобы на самом деле закодировать его как граф, причем состояния как узлы и условия как направленные ребра. Затем шаблон посетителя можно использовать для применения графика для разных целей. это особенно хорошо отразилось бы на конструкциях, в которых состояния и/или переходы могли бы определяться пользователем, но, вероятно, были бы более интенсивными в памяти, чем жестко закодированные машины состояний, описанные в других ответах.
Ответ 6
Структура государственного образца работает над концепцией изменения состояния. Весь жизненный цикл процесса можно разделить на несколько этапов. С завершением каждого фазового процесса происходит выход из одного состояния и переход в другое состояние.
Например, в рамках JSF весь жизненный цикл ответа на запрос веб-запроса делится на шесть фаз:
После завершения каждого этапа процесс выходит из состояния и переходит в другое состояние. Например, после RestoreValuePhase мы можем сказать, что ViewRestored в качестве состояния выхода и RequestApply в качестве состояния ввода.
Итак, чтобы реализовать шаблон проектирования штата, необходимо разделить весь процесс таким образом, чтобы его можно было обрабатывать в нескольких фазах с каждым выходом фазы, определяющим изменение состояния.
Теперь давайте понять это с помощью ниже кода.
Любой жизненный цикл проекта можно разделить на несколько фаз, например
requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure
Итак, это фазы, используемые в приведенном ниже примере
Правила:
-
Нам нужно определить класс, в котором мы можем сохранить текущее состояние процесса. Класс NextPhase в нижнем коде делает это.
-
Нам нужно определить интерфейс, в котором мы можем предоставить контактный метод, который будет реализован в каждой фазе. В ниже кода ProjectPhase делает это.
Подробнее о шаблоне государственного дизайна здесь Государственный шаблон дизайна
http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent