Конечный автомат на основе перечислений Java (FSM): передача событий
Я использую несколько конечных автоматов на основе enum в своем приложении для Android. Хотя они работают очень хорошо, я ищу предложение о том, как элегантно получать события, обычно из зарегистрированных обратных вызовов или сообщений 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)
каждого состояния, и (б) прохождение через дополнительные параметры выглядит неловко.
Я хотел бы предложить элегантное решение для этого, не прибегая к использованию библиотеки.