简体   繁体   English

在嵌套枚举实现接口中继承泛型类型

[英]Inherit generic type in nested enum implementing interface

I try to write a generic abstract class for my state machine, that will be utilizing enum implementing some interface defined inside that abstract class.我尝试为我的状态机编写一个通用抽象类,它将利用枚举实现在该抽象类中定义的一些接口。 I have an abstract class which contains a field implementing a generic interface and some wrapper functions for state switching logic.我有一个抽象类,它包含一个实现通用接口的字段和一些用于状态切换逻辑的包装函数。 I try to extend this abstract class and create nested enum type implementing this generic interface, but there are some places, where I have to define explicitely which types I am using for generics.我尝试扩展这个抽象类并创建嵌套的枚举类型来实现这个泛型接口,但是在有些地方,我必须明确定义我将哪些类型用于泛型。 The code below demostrates this problem下面的代码演示了这个问题

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{
         // ...
      }

   }
}

The main concern is that type information is defined in multiple places in extending class - once in type info of the abstract class and onec in interface the enum implements.主要关注的是类型信息在扩展类中的多个位置定义 - 一次在抽象类的类型信息中和枚举实现的接口中的 onec 中。

FiniteStateMachine is abstract and not an interface because I need some flags and initial state fields (and I can't make an "abstract field" otherwise than with protected constructor hack). FiniteStateMachine 是抽象的而不是接口,因为我需要一些标志和初始状态字段(除了受保护的构造函数黑客之外,我无法创建“抽象字段”)。 FiniteStateMachine.State is an interface, because it's used in enums which cannot be extended. FiniteStateMachine.State 是一个接口,因为它用于无法扩展的枚举中。 I also want to keep FiniteStateMachine and FiniteStateMachineState in one file, because separate fiels create lots of bloat content in project.我还想将 FiniteStateMachine 和 FiniteStateMachineState 保存在一个文件中,因为单独的字段会在项目中创建大量膨胀内容。 Also inside extending FSM the onExit method has a type of State instead of FSMStage.同样在扩展 FSM 中, onExit方法具有一种 State 而不是 FSMStage。

I tried something like FiniteStateMachine<C, I, State<C, I>> but errors said that 'State is not accessible in the context'.我尝试了类似FiniteStateMachine<C, I, State<C, I>>但错误提示“状态在上下文中不可访问”。

Is there any way to declare the types in one place in extending class instead of FSM and FSMState like right now?有没有办法在扩展类中的一个地方声明类型,而不是像现在这样的 FSM 和 FSMState? Or maybe there is a way to declare types only for FSMState and make FSM reuse those types?或者也许有一种方法可以只为 FSMState 声明类型并使 FSM 重用这些类型? Or maybe this design is completely flawed?或者这个设计是完全有缺陷的?

The point is that inner interfaces (and enums too btw) are implicitely static, so they cannot use generic parameters of outer class, because they have no access to instances of the outer class.关键是内部接口(顺便说一下,还有枚举)是隐式静态的,因此它们不能使用外部类的泛型参数,因为它们无法访问外部类的实例。

So basically this interface is inside the abstract class only for code convenience, you may aswell extract it to separate file.所以基本上这个接口在抽象类里面只是为了代码方便,你也可以把它提取到单独的文件中。 In this design I don't think there is a way to skip multiple generic type declarations.在这个设计中,我认为没有办法跳过多个泛型类型声明。

I think changing the design just to avoid the re-declaration is not worth it - you could make State an abstract class and remove generic types from declaration so it gets generic types from the outer class, but then the idea with enums doesn't work.我认为仅仅为了避免重新声明而改变设计是不值得的——你可以让State成为一个抽象类并从声明中删除泛型类型,这样它就可以从外部类中获取泛型类型,但是枚举的想法不起作用.

C in FiniteStateMachine is not the same C in State class, If you want to make them dependent, you have to define a third type in your FiniteStateMachine which uses C and I with State . CFiniteStateMachine是不一样的CState级,如果你想使他们依赖,你必须定义在你的第三类FiniteStateMachine它采用CIState You were almost right with FiniteStateMachine<C, I, State<C, I>> , but here how you can do it :您对FiniteStateMachine<C, I, State<C, I>>几乎是正确的,但在这里您可以这样做:

public abstract class FiniteStateMachine<C, I, T extends FiniteStateMachine.State<C, I>> {
    private T currentState;
    protected FiniteStateMachine(T initial){ currentState = initial; }

    public synchronized void process(C context, I input) {
        FiniteStateMachine.State<C, I> nextState = currentState.process(context, input);
        if(currentState != nextState){
            currentState.onExit(nextState, context);
            State<C, I> previousState = currentState;
            currentState = (T) nextState;
            nextState.onEnter(previousState, context);
        }
    }

    public interface State<CTX, INPT> {
        State<CTX, INPT> process(CTX context, INPT input);
        default void onEnter(State<CTX, INPT> s, CTX context) {}
        default void onExit(State<CTX, INPT> s, CTX context) {}
    }
}

Now you force the types of State to be same as those defined in FiniteStateMachine .现在,您强制State的类型与FiniteStateMachine定义的类型相同。

You can use it now like :你现在可以像这样使用它:

public class FSM extends FiniteStateMachine<Date, String, FSM.FSMState> { 
    public FSM() { super(FSMState.START); }

    public enum FSMState implements FiniteStateMachine.State<Date, String> {
        START{
            @Override
            public FSMState process(Date p, String s) {
                // ...
                return NEXT;
            }

            @Override
            public void onExit(FiniteStateMachine.State s, Date d) { /* ... */ }
        },
        NEXT{
            @Override
            public FiniteStateMachine.State<Date, String> process(Date context, String input) {
                return null;
            }
            // ...
        }
    }
}

Otherwise, what about repeating the generic types !?否则,重复泛型类型怎么办!? From what i've learned so far, there's no way to simplify the writing of your classes.从我到目前为止所学到的,没有办法简化你的类的编写。 I think the origin of your question was when the two classes are declared in the same file.我认为你的问题的起源是两个类在同一个文件中声明的时间。 What if they were separated in two different files ?如果它们被分成两个不同的文件怎么办? Do you continue thinking this way ?你继续这样想吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM