Задача шаблона проектирования, включающая N состояний и переходы между ними - PullRequest
18 голосов
/ 13 января 2010

У меня проблема под рукой, и я не понимаю, какой шаблон проектирования использовать. Проблема выглядит так:

Я должен построить систему, которая имеет N состояний, и моя система должна перейти из любого состояния в любое другое состояние в зависимости от некоторых условий. Пример: При условии 1, переходе из состояния 1 в 3 и в состояние 2 из состояния 1 в 4.

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

Например, переход из состояния 1 в состояние 3 можно выполнить, когда:
условие 1: "Это воскресенье"
условие 2: «Идет дождь»
условие 3: «Идет дождь и воскресенье»
В каждом состоянии обработка в состоянии 3 может быть разной.

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

Большое спасибо

Ответы [ 6 ]

36 голосов
/ 14 января 2010

Это явно случай конечного автомата, но лучше комбинировать условия, а не создавать новые условия для каждой комбинации. Мне не понравился пример 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)
13 голосов
/ 13 января 2010

Это звучит как типичное использование для конечного автомата

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

в коде вы можете сделать конечный автомат, как это:

 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 ... Я больше увлекаюсь C #

9 голосов
/ 13 января 2010

не будет ли шаблон состояния работать?

1 голос
/ 26 сентября 2013

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

Например, в JSF Framework весь жизненный цикл ответа веб-запроса делится на шесть фаз:

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

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

Теперь давайте разберемся с приведенным ниже кодом.

Любой жизненный цикл проекта можно разделить на несколько этапов, например

requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure

Итак, эти фазы используются в следующем примере

Правила:

  1. Нам нужно определить класс, в котором мы можем хранить текущее состояние процесса. Класс NextPhase в приведенном ниже коде делает это.

  2. Нам нужно определить интерфейс, в котором мы можем предоставить метод контакта, который будет реализован на каждом этапе. В коде ниже ProjectPhase это делает.

Узнайте больше о Государственном шаблоне проектирования здесь - Государственный Шаблон проектирования

http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent

1 голос
/ 14 января 2010

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

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

1 голос
/ 13 января 2010

Первое, что я заметил в вашем примере, было то, что State 3 = (State 1 == true && State 2 == true). Это не очень хорошо масштабируется, так как в дело вступает больше возможных государств. Если вы думаете только о том, идет ли дождь или воскресенье, у вас может быть такое перечисление с 4 возможными типами:

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

Это позволит вам четко указывать условия в блоке переключателей, когда пришло время кодировать. Но если вам также нужно рассмотреть, тепло ли это снаружи, вам нужно добавить еще 4 значения в этот список, чтобы охватить все возможные условия. А позже в вашем проекте вашему коду может потребоваться выполнить больше условий, чем вы предполагаете.

Что касается шаблона проектирования, то шаблон State и его пример Java в Википедии выглядят как хорошее место для начала.

В примере Wikipedia есть класс StateContext с методом setState, который принимает имя. Я подумал о том, чтобы предложить добавить здесь логику определения состояния, но это заставит ваш класс StateContext быть слишком близким к деталям реализации других ваших классов. Было бы лучше поместить метод определения состояния системы в классе, который бы легко знал условия перехода из одного состояния в другое. Таким образом, если ваш проект должен измениться в будущем, и у вас будет больше состояний для отслеживания или других условий, вам нужно будет поддерживать логику только в одном месте.

...