Проблема проектирования шаблона с участием 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... Я больше в С#

Ответ 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