我试图创建一个使用枚举来指定状态的状态机。由于存在很多状态并且每个状态实现的逻辑非常复杂,我想将每个状态与将在不同类中定义的状态处理程序相关联。每个状态处理程序都会实现一个公共接口(或扩展一个公共抽象类),但每个状态处理程序可能都有自己的一组注入依赖项,其他人可能不需要。到目前为止,这样的事情......
StateHandler接口:
public interface StateHandler {
void onActivation();
void onDeactivation();
}
StateHandlers示例:
@Singleton
public class DefaultStateHandler implements StateHandler {
@Inject
public DefaultStateHandler(SomeDependency someDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
@Singleton
public class OtherStateHandler implements StateHandler {
@Inject
public OtherStateHandler(SomeOtherDependency someOtherDependency) {...}
/** implement onActivation, onDeactivation and state specific logic **/
}
StateManager实施:
@Singleton
public class StateManager {
private StateType stateType = StateType.DEFAULT;
@Inject
public StateManager() { }
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateType.getStateHandler().onDeactivation();
stateType = newStateType;
stateType.getStateHandler().onActivation();
}
}
}
枚举定义:
public enum StateType {
DEFAULT (/* not sure what to do here */),
OTHER_STATE (...);
private StateHandler stateHandlerInstance;
public getStateHandler { return stateHandlerInstance; }
StateType(/* not sure what to do here */) {
/* assign stateHandlerInstance */
}
}
我想弄清楚的是......在声明相关枚举时,如何注入状态处理程序的特定实例?或者,如果这是不可能的,是否有另一种方法为每个枚举指定状态处理程序类,然后(在构造函数中或在第一次需要时),获取关联的状态处理程序实例?
答案 0 :(得分:0)
我原本以为我需要将状态处理程序实例注入状态枚举定义。但是,由于注入需要公共构造函数和枚举使用私有构造函数,我不认为这种方法是可行的。
正如上面的评论所述,解决方案是使用地图多重绑定。
首先简化枚举StateType:
public enum StateType {
DEFAULT, OTHER_STATE
}
现在我们需要一个特定于此枚举类型的匕首MapKey接口:
@MapKey
@interface StateTypeKey {
StateType value();
}
接下来我们需要一个dagger模块,它将为每个StateType / StateHandler组合提供提供者函数:
@Module
public StateTypeHandlersModule {
// @Provides @IntoMap // Syntax for dagger >= 2.9
@Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
@StateTypeKey(StateType.DEFAULT)
StateHandler provideDefaultStateHandler(DefaultStateHandler handler) {
return handler;
}
// @Provides @IntoMap // Syntax for dagger >= 2.9
@Provides(type = Provides.Type.MAP) // Syntax for dagger <= 2.8
@StateTypeKey(StateType.OTHER_STATE)
StateHandler provideOtherStateHandler(OtherStateHandler handler) {
return handler;
}
}
遗憾的是很多样板代码,这就是为什么我只为处理程序使用一个单独的模块,并将其包含在更高级别的状态机模块中。请注意,如果使用相同的StateTypeKey声明两个提供程序函数,则第二个处理程序最终在注入的映射中可用。
最后,我们可以将Map<StateType, StateHandler>
注入StateManager:
@Singleton
public class StateManager {
private Map<StateType, StateHandler> stateHandlerMap;
private StateType stateType = StateType.DEFAULT;
@Inject
public StateManager(Map<StateType, StateHandler> stateHandlerMap) {
this.stateHandlerMap = stateHandlerMap;
}
public void changeState(StateType newStateType) {
if (stateType != newStateType) {
stateHandlerMap.get(stateType).onDeactivation();
stateType = newStateType;
stateHandlerMap.get(stateType).onActivation();
}
}
}