FSM с состоянием объекта в Java

Я реализую конечный автомат в классах Java. Я не смог найти другого примера, в котором состояния и события были бы их собственными объектами (возможно, для этого есть причина?), и я не совсем уверен в своем решении, особенно потому, что мне нужно присвоить состояние автомату. (фактический менеджер), а затем назначьте FSM состоянию (для уведомления об изменении состояния). Вот код менеджера состояний, которому я назначаю состояние и выдает его, если его попросят:

public class FSM {

    public void setCurrentState(FSMState newCurrentState) {
        this.currentState = newCurrentState;
    }

    private FSMState currentState;

    public FSMState getCurrentState() {
        if (this.currentState == null)
            System.out.println("No current state");
        return this.currentState;
    }
}

и вот состояние, которое использует карту для сопоставления события с выходным состоянием и в случае перехода уведомляет класс FSM:

public class FSMState implements EventListener {

    private FSM managingFSM;
    private Map<Event,FSMState> transitions;

    public FSMState(FSM managingFSM) {
        this.transitions = new HashMap<Event, FSMState>();
        this.managingFSM = managingFSM;
    }

    public void addEventTransition(Event event, FSMState outputState){
        transitions.put(event, outputState);
        event.registerListener(this);
    }

    @Override
    public void eventOccured(Event e) {
        FSMState newState = transitions.get(e);
        this.managingFSM.setCurrentState(newState);
    }
}

Есть ли способ с похожим решением, чтобы государству не пришлось уведомлять управляющего?


person Nicolas Mattia    schedule 25.08.2013    source источник
comment
Это выглядит очень подверженным ошибкам. Когда вы добавляете переходы событий в FSMStates? Потому что так, как вы сделали это прямо сейчас, когда происходит событие, оно срабатывает в любом FSMState, в котором оно было зарегистрировано (независимо от текущего состояния), и меняет текущее состояние. Я предполагаю, что вы хотите, чтобы запускались только события для текущего состояния, чтобы вы получили правильный переход.   -  person Illidanek    schedule 22.05.2014


Ответы (1)


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

Сначала измените FSMState, чтобы он был просто таким:

public class FSMState {

    private Map<Event,FSMState> transitions;

    public FSMState() {
        this.transitions = new HashMap<Event, FSMState>();
    }

    public void addEventTransition(Event event, FSMState outputState){
        transitions.put(event, outputState);
    }

    public FSMState transition(Event e) {
        if(transitions.containsKey(e)) {
            return transitions.get(e);
        }
        else {
            System.out.println("No transition found");
            return this;
        }
    }

}

Затем измените класс FSM, чтобы он выглядел следующим образом:

public class FSM implements EventListener {

    private FSMState currentState;

    public FSM(FSMState startState) {
        currentState = startState;
    }

    public FSMState getCurrentState() {
        if (this.currentState == null)
            System.out.println("No current state");
        return this.currentState;
    }

    @Override
    public void eventOccured(Event e) {
        currentState = currentState.transition(e);
    }
}

Наконец, добавьте менеджер для инициализации всего:

public class FSMManager {

    private static final NUM_STATES = 5;

    public static void main(String[] args) {

         FSMState[] states = new FSMState[NUM_STATES];

         for(FSMState state : states) {
             state = new FSMState();
         }

         // Then add all the state transitions to all the states
         states[0].addEventTransition(event1, states[1]);
         states[1].addEventTransition(event1, states[2]);
         states[1].addEventTransition(event2, states[4]);
         // etc, etc

         //Finally, create the FSM
         FSM fsm = new FSM(state[0]);

         //You will also have to register the FSM to listen for all the events
         event1.registerListener(fsm);
         event2.registerListener(fsm);
         ...


    }

}

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

Это решение должно помочь, однако оно не идеально, так как я точно не знаю, как вы это делаете, поэтому, если у вас есть какие-либо вопросы/дополнительные проблемы, прокомментируйте, и я постараюсь улучшить свой ответ.

person Illidanek    schedule 22.05.2014