【问题标题】:Enum abstraction problem枚举抽象问题
【发布时间】:2011-07-29 04:27:14
【问题描述】:

我目前正在努力解决 Java 抽象问题。我有这样的事情:

public interface State {
};

public interface Dynamics {
  getObservationChance(State state, Observation observation);
};

class SpecialState implements State {
};

enum SpecialObservation() {
  FREE, WALL, etc.
}

class SpecialDynamics implements Dynamics {
   getObservationChance(State state, Observation observation) {
       // state should be SpecialState, observation should be SpecialObservation!
   }
};

class Main {
  Main(State state, Observation observation, Dynamics dynamics) {
      dynamics.getObservationChance(state, observation);
   }
};

SecialObservation 应该是可能观察的枚举(或类似的东西),但我想对问题进行抽象表示。所以我想要一个 Observation 应该包含观察结果一个返回所有可能观察结果列表的函数。最后一点对于我正在实现的算法非常重要,因为我必须总结所有可能的观察结果。

谢谢!

【问题讨论】:

    标签: java enums abstraction


    【解决方案1】:

    使用接口:

    interface Observation{  
      Collection<Observation>getSubObservations();
    }
    
    enum SpecialObservation implements Observation {
      FREE, 
      DOOR (FREE),
      WINDOW (FREE),
      WALL (DOOR, WINDOW, FREE);
    
      private Collection<Observation> subObservations;
    
      private SpecialObservation(Observation... subObservations) {
        this.subObservations = subObservations;
      }
    
      public Collection<Observation> getSubObservations() {
        return subObservations;
      }
    }
    

    【讨论】:

      【解决方案2】:

      您可以在枚举中添加方法:

      enum SpecialObservation() implements Observation{
        FREE{
          void doSth(){
          }
      
          Collection<Observation> getPossibleObservations{
          }
        }, WALL, etc.
      }
      

      【讨论】:

      • 您是否建议我应该为每个枚举实现一个 getPossibleObservations?
      • 否,但如果您想限制对对象的可能后续调用,这是一个选项。例如,WALL 只能调用 FENCE,FREE 之后 FANCE 和 WALL 都可以调用。如果您只是返回所有对象的列表,请将此方法放入枚举中,就像在@Thomas 回答中一样。
      【解决方案3】:

      由于 Java 实现枚举的方式,不可能有抽象枚举,如果设计正确,您将不会觉得需要抽象枚举。但是,据我记得,您可以在枚举中定义自己的方法...(您可能需要检查一下...我已经有一段时间没有接触 Java了)

      【讨论】:

        【解决方案4】:

        这里需要参数化类型 - 每个树类型都有一系列:状态、观察和动态。

        如果我们将观察枚举作为参数类型,我们可以将您的类型转换为如下形式:

        public interface Observation<O extends Observation<O>> {
            ...
        }
        
        public interface State<O extends Observation<O>> {
        }
        
        public interface Dynamics<O extends Observation<O>> {
          getObservationChance(State<O> state, O observation);
        }
        
        enum SpecialObservation implements Observation<SpecialObservation> {
          FREE, WALL, etc.
        }
        
        class SpecialState implements State<SpecialObservation> {
        }
        
        
        class SpecialDynamics implements Dynamics<SpecialObservation> {
           getObservationChance(State<SpecialObservation> state, SpecialObservation observation) {
               // state should be SpecialState, observation should be SpecialObservation!
           }
        }
        
        class Main<O extends Observation> {
          Main(State<O> state, O observation, Dynamics<O> dynamics) {
              dynamics.getObservationChance(state, observation);
           }
        }
        

        当然,只有当我们的 State 接口的方法对于 getObservationChance 方法足够时,这种方法才有效。

        更通用的方法是对所有三种类型进行参数化:

        public interface Observation<O extends Observation<O, S, D>,
                                     S extends State<O,S,D>,
                                     D extends Dynamics<O,S,D>>
        {
            ...
        }
        
        public interface State<O extends Observation<O,S,D>,
                               S extends State<O,S,D>,
                               D extends Dynamics<O,S,D>> {
        }
        
        public interface Dynamics<O extends Observation<O,S,D>,
                                  S extends State<O,S,D>,
                                  D extends Dynamics<O,S,D>> {
          getObservationChance(S state, O observation);
        }
        

        然后我们可以这样定义实现:

        enum SpecialObservation implements Observation<SpecialObservation, SpecialState, SpecialDynamics> {
          FREE, WALL, etc.
        }
        
        class SpecialState implements State<SpecialObservation, SpecialState, SpecialDynamics> {
        }
        
        
        class SpecialDynamics implements Dynamics<SpecialObservation, SpecialState, SpecialDynamics> {
           getObservationChance(SpecialObservation state, SpecialObservation observation) {
               // state should be SpecialState, observation should be SpecialObservation!
           }
        }
        

        当然,主类需要所有三个参数:

        class Main<O extends Observation<O,S,D>,
                   S extends State<O,S,D>,
                   D extends Dynamics<O,S,D>> {
          Main(S state, O observation, D dynamics) {
              dynamics.getObservationChance(state, observation);
           }
        }
        

        实际上,在您的情况下,动态仅取决于观察和状态,而不是相反(并且它们彼此不依赖),因此另一种方式是:

        public interface Observation {
            ...
        }
        
        public interface State {
        }
        
        public interface Dynamics<S extends State,
                                  O extends Observation> {
          getObservationChance(S state, O observation);
        }
        
        enum SpecialObservation implements Observation {
          FREE, WALL, etc.
        }
        
        class SpecialState implements State {
        }
        
        
        class SpecialDynamics implements Dynamics<SpecialState, SpecialObservation> {
           getObservationChance(SpecialState state, SpecialObservation observation) {
               // state should be SpecialState, observation should be SpecialObservation!
           }
        }
        
        class Main<S extends State, O extends Observation> {
          Main(S state, O observation, Dynamics<S, O> dynamics) {
              dynamics.getObservationChance(state, observation);
           }
        }
        

        编辑: 关于 getAllObservations 方法: 只要你能以某种方式使你的类型参数具体化,这里就没有真正的问题。 要访问特定类型的枚举常量列表,您需要访问此类型 - 可以直接访问 (SpecialObservation.values()),也可以使用如下所示的类对象:

        class Main<S extends State, O extends Observation> {
        
          public O[] getAllObservations(Class<O> oClass) {
             return oClass.getEnumConstants();
          }
        
          Main(S state, Dynamics<S, O> dynamics, Class<O> observationClass) {
              O[] observations = getAllObservations(observationClass);
              for(O o : observations) {
                 dynamics.getObservationChance(state, observation);
              }
           }
        }
        

        (当然,这只适用于 O 是枚举类的情况。)

        如果您有一个混合列表,它会变得更加复杂,并且类型安全地匹配 Dynamics、Action、Observation 和 State 类也不是一件容易的事。

        【讨论】:

        • 同理还有一个Action和SpecialAction。我有一个关于 Main 的问题,因为我实际上没有给出 Observation 参数,但我应该从 getAllObservations() 开始。那么您的方法是否适用于 Observation 中的静态 getAllObservations() 方法?看起来确实如此,但我不确定。
        • SpecialState、SpecialAction 等是否需要其他 State/Action 没有的方法(可从外部访问)(或者不能放在通用接口中)?这会稍微简化这个过程(从那时起我们就不需要太多参数化了)。
        • 您的getAllObservations 是否返回不同观察类型的混合列表,或所有相同类型的观察?
        • SpecialState 确实有一些 SpecialDynamics 可以使用的特殊功能,但也许我可以在 SpecialDynamics 中从 State 转换到 SpecialState。恐怕 getAllObservations 是个问题,因为我无法在 Observation 接口中定义静态函数。编辑:getAllObservations 应该只返回相同 SpecialObservation 类型的元素。
        • 啊,getAllObservations 应该简单地创建所有定义的观察枚举的联合?放到另一个类里,这不是这里的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多