В моем приложении для Android я использую несколько состояний на основе enum. Хотя они работают очень хорошо, то, что я ищу, - это предложение о том, как элегантно принимать события, как правило, из зарегистрированных обратных вызовов или из сообщений eventbus, в текущее активное состояние. Из многих блогов и руководств, посвященных FSM на основе перечислимого типа, большинство из них приводят примеры состояний машин, которые потребляют данные (например, парсеров), а не показывают, как эти FSM могут управляться из событий.
Типичный конечный автомат, который я использую, имеет следующую форму:
private State mState;
public enum State {
SOME_STATE {
init() {
...
}
process() {
...
}
},
ANOTHER_STATE {
init() {
...
}
process() {
...
}
}
}
...
В моей ситуации некоторые из состояний запускают часть работы над конкретным объектом, регистрируя слушателя. Этот объект асинхронно перезвонит, когда работа будет выполнена. Другими словами, просто простой интерфейс обратного вызова.
Аналогично, у меня есть EventBus. Классы, желающие получать уведомления о событиях, снова реализуют интерфейс обратного вызова и listen()
для этих типов событий в EventBus.
Основная проблема заключается в том, что конечный автомат или его отдельные состояния или класс, содержащий перечислимый FSM, или что-то должно реализовать эти интерфейсы обратного вызова, чтобы они могли представлять события в текущем состоянии.
Один из подходов, который я использовал, предназначен для всего enum
для реализации интерфейса (-ов) обратного вызова. Само перечисление имеет стандартные реализации методов обратного вызова внизу, и отдельные состояния могут затем переопределять эти методы обратного вызова для событий, которые им интересны. Чтобы это работало, каждое государство должно регистрироваться и отменить регистрацию при входе и выходе, иначе существует риск обратного вызова в состоянии, которое не является текущим состоянием. Я, вероятно, придерживаюсь этого, если не найду ничего лучшего.
Другой способ заключается в том, чтобы класс-класс выполнял обратные вызовы. Затем он должен делегировать эти события на конечный автомат, вызывая mState.process( event )
. Это означает, что мне нужно будет перечислять типы событий. Например:
enum Events {
SOMETHING_HAPPENED,
...
}
...
onSometingHappened() {
mState.process( SOMETHING_HAPPENED );
}
Мне это не нравится, потому что (а) у меня было бы уродство необходимости switch
для типов событий в process(event)
каждого состояния, и (b) прохождение дополнительных параметров выглядит неудобно.
Я хотел бы предложить элегантное решение для этого, не прибегая к использованию библиотеки.