基于Java枚举的状态机(FSM):传递事件

我在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 );

}

但是,我不喜欢这样,因为(a)我需要在每个状态下处理switch事件类型process(event),并且(b)传递其他参数看起来很尴尬。

我想提出一个优雅的解决方案的建议,而不必诉诸使用库。

回答:

因此,您想将事件调度到其当前状态的处理程序。

要调度到当前状态,在每个状态变为活动状态时对其进行订阅,而在其变为非活动状态时对其进行取消订阅则非常麻烦。订阅知道活动状态的对象比较容易,只需将所有事件委托给活动状态即可。

要区分事件,可以使用单独的事件对象,然后使用visitor模式来区分它们,但这是很多样板代码。仅当我有其他代码将所有事件都视为相同时(例如,如果事件必须在交付前进行缓冲),我才会这样做。否则,我只会做类似的事情

interface StateEventListener {

void onEventX();

void onEventY(int x, int y);

void onEventZ(String s);

}

enum State implements StateEventListener {

initialState {

@Override public void onEventX() {

// do whatever

}

// same for other events

},

// same for other states

}

class StateMachine implements StateEventListener {

State currentState;

@Override public void onEventX() {

currentState.onEventX();

}

@Override public void onEventY(int x, int y) {

currentState.onEventY(x, y);

}

@Override public void onEventZ(String s) {

currentState.onEventZ(s);

}

}

如果事件类型很多,最好在运行时使用字节码工程库甚至是普通的JDK代理生成无聊的委托代码:

class StateMachine2 {

State currentState;

final StateEventListener stateEventPublisher = buildStateEventForwarder();

StateEventListener buildStateEventForwarder() {

Class<?>[] interfaces = {StateEventListener.class};

return (StateEventListener) Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

try {

return method.invoke(currentState, args);

} catch (InvocationTargetException e) {

throw e.getCause();

}

}

});

}

}

这使代码的可读性较差,但确实消除了为每种事件类型编写委派代码的需要。

以上是 基于Java枚举的状态机(FSM):传递事件 的全部内容, 来源链接: utcz.com/qa/417765.html

回到顶部