Enum проблема абстракции - PullRequest
1 голос
/ 04 апреля 2011

В настоящее время я борюсь с проблемой абстракции 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 должно быть перечислением (или что-то в этом роде) возможных наблюдений, но я хочу иметь абстрактное представление проблемы.Поэтому я хочу, чтобы Наблюдение содержало наблюдение и функцию, которая возвращает список всех возможных наблюдений.Последнее очень важно для алгоритма, который я реализую, так как я должен обобщить все возможные наблюдения.

Спасибо!

Ответы [ 4 ]

3 голосов
/ 04 апреля 2011

Здесь вам нужны параметризованные типы - у вас есть семейства типов деревьев: состояние, наблюдение и динамика.

Если мы берем перечисление наблюдения в качестве типа параметра, мы можем преобразовать ваш тип вчто-то вроде этого:

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: Пока вы каким-то образом можете конкретизировать параметры вашего типа, здесь нет никаких реальных проблем.Чтобы получить доступ к списку констант enum определенного типа, вам нужен доступ к этому типу - либо напрямую (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.

2 голосов
/ 04 апреля 2011

Вы можете добавить методы к своим перечислениям:

enum SpecialObservation() implements Observation{
  FREE{
    void doSth(){
    }

    Collection<Observation> getPossibleObservations{
    }
  }, WALL, etc.
}
1 голос
/ 04 апреля 2011

Использовать интерфейс:

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;
  }
}
0 голосов
/ 04 апреля 2011

Из-за того, как Java реализует перечисления, невозможно иметь абстрактные перечисления, и при правильном дизайне вы не почувствуете необходимости в них.Тем не менее, насколько я помню, вы можете определить свои собственные методы в enum ... (возможно, вам придется это проверить. Я уже некоторое время не общался с Java)

...