基于枚举的状态机,Dagger2注入状态处理程序



我正在尝试创建使用枚举来指定状态的状态计算机。由于有很多状态,并且每个州实现的逻辑非常复杂,因此我想将每个状态与将在其他类中定义的状态处理程序相关联。每个状态处理程序将实现一个通用的接口(或扩展一个常见的摘要类(,但是每个界面可能都有其其他可能不需要的注入依赖项。到目前为止,这样的东西....

StateHandler接口:

public interface StateHandler {
    void onActivation();
    void onDeactivation();
}

示例状态人:

@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 */
    }
}

我要弄清楚的是...在声明其相关枚举时,如何注入状态处理者的特定实例?或者,如果不可能,是否有另一种方式来指定每个枚举的状态处理程序类,然后(在构造函数中或第一个需要时(,获取关联的状态处理程序实例?

<?

我最初认为我需要将州的处理程序实例注入状态枚举定义。但是,由于注射需要公共建筑商和枚举使用私人构造函数,因此我认为这种方法是可行的。

如上所述,解决方案是使用MAP多键。

首先简化了枚举刻板:

public enum StateType {
    DEFAULT, OTHER_STATE
}

现在我们需要特定于此枚举类型的daggermapkey接口:

@MapKey
@interface StateTypeKey {
    StateType value();
}

接下来,我们需要一个dagger模块,该模块将为每个刻板类型/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();
        }
    }
}

最新更新