У меня есть проблема под рукой, и я не добираюсь который шаблон разработки использовать. Проблема идет как таковая:
Я должен создать систему, которая имеет состояния 'N', и моя система должна сделать переход от любого состояния до любого другого состояния в зависимости от некоторых условий. Исключая: При условии 1, перемещение от состояния 1 - 3 и при условии 2 от состояния 1 - 4.
Даже переход от одного состояния до другого состояния может быть сделан на 2 или больше различных условиях.
Например, переход от состояния 1 для утверждения 3 может быть сделан когда:
условие 1: "Воскресенье"
условие 2: "То, что это лилось дождем"
условие 3: "То, что это лилось дождем и в воскресенье"
В каждом условии обработка в состоянии 3 может отличаться.
Я надеюсь, что смог понять проблему четко. Доброжелательная справка.
Большое спасибо
Ясно случай с конечным автоматом, но лучше, чтобы объединить условия, а не создать новое условие для каждой комбинации. Мне не нравился пример Java за образец состояния на Википедию, как состояния знают о других состояниях, которые не имели бы смысла в большом количестве сценариев. Таблица перехода, которая отслеживает от состояние, применимое условие (условия) , и к состояние, помогает заботиться о той проблеме.
Мои два цента для object oriented-finite-state-machine. Существуют улучшения, которые вы могли сделать на передней стороне 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
у меня был горький опыт с использованием конечного автомата для довольно крупного проекта. Проблема была со сложными государствами. Точно так же, как составное условие вы упомянули (в воскресенье и льющийся дождем), могли технически быть сложные государства, которые могли далее быть разломаны на состояния единицы. Это может или не может иметь место в вашей ситуации, но все еще стоящий упоминания. Если это так, лучше изменять классический конечный автомат и использовать набор состояний вместо единственного состояния для представления от и до состояний. Если ваш N будет большим, то это поможет сохранить уровни исправности в целости. Думать папки Hotmail по сравнению с тэгами Gmail. Таблица перехода была бы затем представлена как
Transition(Set<State> from, Set<Condition> conditions, Set<State> to)
Если аргумент только входное STD :: string
Как это
std::string text("Hello");
w32function(text.c_str());
Если аргумент вход / вывод Использование STD :: Vector
Вместо этого:
std::string input("input");
std::vector<char> input_vec(input.begin(), input.end());
input_vec.push_back('\0');
w32function(&input_vec[0], input_vec.size());
// Now, if you want std::string again, just make one from that vector:
std::string output(&input_vec[0]);
Если аргумент - только выход также использовать STD :: Vector
, как это:
// allocates _at least_ 1k and sets those to 0
std::vector<unsigned char> buffer(1024, 0);
w32function(&buffer[0], buffer.size());
// use 'buffer' vector now as you see fit
Вы также можете использовать std :: basic_string
и std :: vector
, если это необходимо.
Вы можете прочитать больше на тему в книге Эффективным STL Скотт Мейерс.
-121--3791990-Первое, что я заметил в вашем примере, это состояние 3 = (состояние 1 == True && State 2 == TRUE). Это не будет масштабироваться очень хорошо, как вовлечены более возможные состояния. Если вы рассматриваете только, стоит ли идти дождь или в воскресенье, вы можете иметь в воскресенье, у вас может быть перечисление, с 4 возможными типами:
enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }
Это позволит вам очистить условия чисто в блоке переключателя, когда настало время для кода. Но если вы также должны рассмотреть, тепло его на улице, вы должны добавить еще 4 значения для захвата всех возможных условий. А позже в вашем проекте ваш код может потребоваться запечатлеть больше условий, чем вы в настоящее время представите.
Что касается структуры дизайна, узор состояния и его пример Java на Wikipedia выглядят как хорошее место для начала.
Пример Википедии имеет StateContext
класс со способом, называемым SetState
, который принимает имя. Я подумал, что вы предложили, что вы добавляете логику определения состояния здесь, но это сделало бы вашу StateContext
классом классом. Было бы лучше поставить метод определения состояния системы в классе, который бы легко узнал условия для перехода от одного государства в другое. Таким образом, если ваш проект должен измениться в будущем, и у вас есть больше государств для отслеживания или разных условий, вам нужно только поддерживать логику в одном месте.
Это походит на типичное использование для конечный автомат
короче говоря, конечный автомат описывает различные состояния, в которых ваша система может быть, и под которыми условиями это может пойти в зависимости от государства. Конечный автомат описан точно как ваше английское описание. И это может быть официально описано с помощью диаграммы состояний
в коде, вы могли сделать конечный автомат как это:
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#
Как и другие, говорили, что государственный аппарат может быть смоделирован в процедурном коде с выключателем или в коде OO с шаблоном состояния, который, вероятно, что вы были после.
Однако 3-й способ - фактически кодировать его как график, с состояниями как узлы и условия в качестве направленных ребер. Затем рисунок посетителей может использоваться для применения графика к другому применению. Это обеспечит особенно хорошо конструирует, где могут быть определены состояния и / или переходы, но, вероятно, будут более интенсивно памятью, затем жесткими кодированными станками, описанными в других ответах.