2010-04-26 4 views
3

Я хочу смоделировать своего рода FSM (конечный автомат). У меня есть последовательность состояний (скажем, от StateA до StateZ). Эта последовательность называется цепочкой и реализуется внутри как Список. Я добавлю состояния по порядку, который я хочу, чтобы они запускались.Проектирование цепочки состояний

Моя цель - сделать последовательность действий на моем компьютере (например, щелчками мыши). (Я знаю, что это было сделано миллион раз).

Так состояние определяется как:

  1. boolean Precondition() < - Проверяет, является ли для этого состояния, некоторое условие истинно. Например, если я хочу нажать кнопку «Запись» программы, в этом методе я бы проверил, работает ли процесс программы или нет. Если это так, перейдите к следующему состоянию в списке цепочек, в противном случае перейдите к тому, что было определено как состояние отказа (обычно это первое состояние из всех).
  2. IState GetNextState() < - Возвращает следующее состояние для оценки. Если условие Precondition() было успешным, оно должно привести к следующему состоянию в цепочке, иначе оно должно привести к состоянию отказа.
  3. Run() Просто проверяет Precondition() и устанавливает внутренние данные, поэтому GetNextState() работает должным образом.

Так, наивный подход к этому было бы что-то вроде этого:

Chain chain = new Chain(); 
//chain.AddState(new State(Precondition, FailState, NextState) <- Method structure 
chain.AddState(new State(new WinampIsOpenCondition(), null, new <problem here, I want to referr to a state that still wasn't defined!>); 

Большая проблема в том, что я хочу сделать ссылку на государство, которое на данный момент еще не была определена. Я мог бы обойти проблему, используя строки при переходе в состояния и используя внутреннюю хеш-таблицу, но разве нет более ясной альтернативы?

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

ответ

2

Вы можете сделать одно из следующих действий:

  • Определение nextState как изменяемые поля в вашем Sta t е класса и проволоки до государств-потом с помощью мутатор; например setNextState. Метод setNextState может быть реализован только для того, чтобы он вызывался один раз; последующие вызовы вызовут IllegalStateException.
  • Изменить интерфейс State, чтобы просто вернуть, выполняется ли предварительное условие или нет (т. Е. Вернуть boolean) и использовать внешний класс «координатор» для перехода по списку, если выполняется предварительное условие. Другими словами, вы знаете, что следующее состояние находится в индексе i + 1, так что есть нет реальной необходимости для каждого государства иметь явные знания о его преемнике.

Учитывая простоту вашей государственной машины, я бы предпочел второй подход.

1

Это может быть идеальный кандидат для Оформитель шаблон. Следующий шаг украшает (обертывает) текущий шаг. Вы можете построить целую цепь состояний.

1

Я полностью согласен со вторым пунктом от @Adamski.Нет необходимости, чтобы государства позитивно знали о себе, если вы не планируете пересекать состояния как алгоритм графа, а не использовать внешний посредник для управления обходом.

Если вы действительно заинтересованы в штатах на самом деле быть в состоянии быть выражено в виде дерева (даже если он полностью линейны в настоящее время), чтобы ответить на ваш вопрос о new <problem here, I want to referr to a state that still wasn't defined!>);

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

Когда вы дойдете до вызова выполнения, вы должны нажать на последнее действие, которое не находится на контейнере, вместе с действием, которое определяет конец FSM.

Таким образом, вы бы что-то вроде этого

public State PreviousAction { get; set; } 
public IList<State> States { get; private set } 
public void QueueAction(State CurrentAction) 
{  
    if(PreviousAction != null) 
    {   
     States.Add(new State(PreviousAction, CurrentAction)   
    } 

    PreviousAction = CurrentAction;  
} 

public void Execute() 
{  
    States.Add(new State(PreviousAction, State.Terminator)); 

    States[0].Execute();  
} 
Смежные вопросы