Я пытаюсь написать общий абстрактный класс для моего конечного автомата, который будет использовать enum, реализующий некоторый интерфейс, определенный внутри этого абстрактного класса.У меня есть абстрактный класс, который содержит поле, реализующее универсальный интерфейс, и некоторые функции-оболочки для логики переключения состояний.Я пытаюсь расширить этот абстрактный класс и создать вложенный тип enum, реализующий этот универсальный интерфейс, но есть некоторые места, где я должен четко определить, какие типы я использую для универсальных шаблонов.Приведенный ниже код демонстрирует эту проблему
public abstract class FiniteStateMachine<C, I> { // <- generic types declared here
private State<C, I> currentState;
protected FiniteStateMachine(State<C, I> initial){ currentState = initial; }
// some other methods for FSM, that I don't want to include in State<>
// ...
public synchronized void process(C context, I input) {
State<C, I> nextState = currentState.process(context, input)
if(currentState != nextState){
currentState.onExit(nextState, context);
State<C, I> previousState = currentState;
currentState = nextState;
nextState.onEnter(previousState, context);
}
}
public interface State<C, I> { //<- this interface should use the same types as FiniteStateMachine
State<C, I> process(C context, I input);
default void onEnter(State<C, I> s, C context) {}
default void onExit(State<C, I> s, C context) {}
}
}
class FSM extends FiniteStateMachine<Data, String> { // <- here I define types used for FSM
public FSM() { super(FSMStage.START); }
enum FSMState implements State<Data, String> { // <- and here I have to repeat them
START{
@Override
public FSMState process(Data p, String s) {
// ...
return NEXT;
},
@Override
public void onExit(State s, Data d) { /* ... */ }
},
NEXT{
// ...
}
}
}
Основная проблема заключается в том, что информация о типе определяется в нескольких местах в расширяющем классе - один раз в информации о типе абстрактного класса и один в интерфейсе, который реализует enum.
FiniteStateMachine является абстрактным, а не интерфейсом, потому что мне нужны некоторые флаги и поля начального состояния (и я не могу создать «абстрактное поле» иначе, как с помощью взлома защищенного конструктора).FiniteStateMachine.State - это интерфейс, потому что он используется в перечислениях, которые не могут быть расширены.Я также хочу сохранить FiniteStateMachine и FiniteStateMachineState в одном файле, потому что отдельные поля создают много раздувного контента в проекте.Также внутри расширения FSM метод onExit
имеет тип State вместо FSMStage.
Я пробовал что-то вроде FiniteStateMachine<C, I, State<C, I>>
, но в ошибках говорилось, что «State не доступно в контексте».
Есть ли способ объявить типы в одном месте в расширяющем классе вместо FSM и FSMState, как сейчас?Или, может быть, есть способ объявить типы только для FSMState и заставить FSM повторно использовать эти типы?Или, может быть, этот дизайн полностью испорчен?