2013-07-23 3 views
5

Возможно ли как-то пометить определенные значения enum в Java как private-package, т. Е. Дать им модификатор по умолчанию?Видимость значений перечисления в Java

фон (только упредить в противном случае сразу же первый комментарий «Зачем?»;))

У меня есть Task -объекта с различными исполнительными-методами и в исполнении государства, который решает, какой метод вызвать следующий. Каждый из методов выполнения возвращает состояние выполнения следующего метода, который будет вызываться (в основном, рамки для выполнения государственной машины).

У меня есть enum, который содержит все возможные состояния выполнения, но также содержит несколько «внутренних» состояний пакета, таких как «ожидающие» или «неудачные», которые не должны возвращаться с помощью методов выполнения.

Я знаю, что я мог бы управлять этими состояниями в отдельной переменной со своим собственным перечислимого, но это будет сделать код намного менее чистый, как это превращает один switch -statement в (по крайней мере) два (и, возможно, окружающих if). Кроме того, я мог бы, конечно, просто проверить возвращаемое значение, но я бы предпочел не ошибаться в первую очередь.

+3

Нет, вы не можете отметить некоторые константы перечисления public и некоторые частные пакеты. –

+1

В этом случае, возможно, вы можете использовать старые java-перечисления, просто класс с некоторыми конечными статическими константами. – Marcelo

+0

На самом деле вы ничего не можете отметить. Они «публичные», и все. –

ответ

5

Звучит как простой ответ: «Нет."

Но, думая о различных комментариях и ответах (в частности, Марсело, BlackVegetable и OldCurmudgeon), я пришел со следующим обходного:

пакет-частное перечисление содержит все значения:

enum PackagePrivateEnum { 
    PUBLIC_VALUE_1, 
    PUBLIC_VALUE_2, 
    PUBLIC_VALUE_3, 
    PACKAGE_PRIVATE_VALUE_1, 
    PACKAGE_PRIVATE_VALUE_2; 
} 

Второй общественное перечисление содержит только общественные ценности и непосредственно отображает их в пакет-частные:

public enum PublicEnum { 
    PUBLIC_VALUE_1 (PackagePrivateEnum.PUBLIC_VALUE_1), 
    PUBLIC_VALUE_2 (PackagePrivateEnum.PUBLIC_VALUE_2), 
    PUBLIC_VALUE_3 (PackagePrivateEnum.PUBLIC_VALUE_3); 

    final PackagePrivateEnum value; 

    private PublicEnum(PackagePrivateEnum value) { 
     this.value = value; 
    } 
} 

Теперь, если у меня есть функция, которая разрешается только вернуть один из общественных ценностей, я определяю его как:

public abstract PublicEnum returnSomething(); 

, а затем использовать его в пакете с помощью:

PackagePrivateEnum value = returnSomething().value; 

Это скрывает нежелательные значения от общественности и, я считаю, одновременно минимизирует кодирование и производительность накладных расходов внутри пакета (например, нет операторов switch- или if-out, нет поиска по карте и т. д., требуется только .value). Фактически, с помощью интеллектуального компилятора, такого как GWT, возвращаемое значение должно, вероятно, получить «inlined» до такой степени, что даже .value -lookup полностью удаляется, то есть вообще не накладные расходы.

Кроме того, с помощью этого можно определить произвольное количество различных допустимых подмножеств большого коллективного перечисления для разных контекстов: я мог бы легко определить еще один PublicEnum2, который предоставляет совершенно другой набор значений из PackagePrivateEnum.

+0

Этот ответ был тем, к чему я стремился в своих комментариях. +1 – BlackVegetable

+0

@BlackVegetable :) Теперь это имеет смысл! Я добавил вас в список вверх ... :) –

1

У вас возникли трудности, потому что вы используете неправильный шаблон.

Ваш Task s не должен возвращать следующее состояние. Для управления потоком вы должны использовать матрицу State s. Таким образом, ваш поток не запутывается внутри задач, а State остаются закрытыми для системы потока.

Если вы хотите, чтобы ваш Task контролировал поток, они должны что-то вернуть (возможно, успех/отказ) повлиять на контроллер потока. Они не должны определить следующее состояние, они должны влияние следующее состояние.

Добавлено

Вот несколько надуманный пример того, что я имею в виду. Обратите внимание, что Task s прикреплены к каждому State, а поток управляется Map, который просто удерживает каждый переход состояния.

Я предпринял попытку поднять итог, чтобы соответствовать вашим возвращающимся результатам, но я подозреваю, что это просто перекомплементивает вопросы, и как только вы охватите разделение потока из состояния, вы поймете, что я пытаюсь объяснить.

public class Test { 
    public void test() { 
    new Thread(new Engine()).start(); 
    } 

    static final Map<State, State> flow = new HashMap<>(); 

    static { 
    flow.put(State.Start, State.A); 
    flow.put(State.A, State.B); 
    flow.put(State.B, State.Finished); 
    } 

    public static class Engine implements Runnable { 
    State state = State.Start; 

    @Override 
    public void run() { 
     while (state != State.Finished) { 
     System.out.println("State: "+state); 
     // Perform all tasks of this state. 
     for (Task task : state.tasks) { 
      System.out.println("Task: "+task); 
      Result result = Result.Start; 
      // Keep performing until completed. 
      while (result != Result.Completed) { 
      System.out.println("Result: "+result); 
      result = result.perform(task); 
      } 
      System.out.println("Result: "+result); 
     } 
     // All tasks performed! Next state. 
     state = flow.get(state); 
     } 
     System.out.println("State: "+state); 
    } 
    } 

    enum State { 
    Start, 
    A(Task.One, Task.Two), 
    B(Task.Two), 
    Finished; 
    Iterable<Task> tasks; 

    State(Task... tasks) { 
     this.tasks = Arrays.asList(tasks); 
    } 
    } 

    enum Result { 
    Start { 
     @Override 
     Result perform(Task t) { 
     return t.initialise(); 
     } 
    }, 
    Executing { 
     @Override 
     Result perform(Task t) { 
     return t.execute(); 
     } 
    }, 
    Finalising { 
     @Override 
     Result perform(Task t) { 
     return t.finalise(); 
     } 
    }, 
    Completed { 
     @Override 
     Result perform(Task t) { 
     // Stop there. 
     return Completed; 
     } 
    }; 

    abstract Result perform(Task t); 
    } 

    enum Task { 
    One { 
     @Override 
     Result initialise() { 
     return Result.Executing; 
     } 

     @Override 
     Result execute() { 
     return Result.Finalising; 
     } 

     @Override 
     Result finalise() { 
     return Result.Completed; 
     } 
    }, 
    Two { 
     @Override 
     Result initialise() { 
     return Result.Executing; 
     } 

     @Override 
     Result execute() { 
     return Result.Finalising; 
     } 

     @Override 
     Result finalise() { 
     return Result.Completed; 
     } 
    }; 

    abstract Result initialise(); 

    abstract Result execute(); 

    abstract Result finalise(); 
    } 

    public static void main(String args[]) { 
    try { 
     new Test().test(); 
    } catch (Throwable t) { 
     t.printStackTrace(System.err); 
    } 
    } 
} 

Добавлено

Упрощая, убрав ваше требование, чтобы контролировать поток через результаты методов задачи получаем:

public class Test { 
    public void test() { 
    new Thread(new Engine()).start(); 
    } 

    static final Map<State, State> flow = new HashMap<>(); 

    static { 
    flow.put(State.Start, State.A); 
    flow.put(State.A, State.B); 
    flow.put(State.B, State.Finished); 
    } 

    public static class Engine implements Runnable { 
    State state = State.Start; 

    @Override 
    public void run() { 
     while (state != State.Finished) { 
     System.out.println("State: "+state); 
     // Perform all tasks of this state. 
     for (Task task : state.tasks) { 
      System.out.println("Task: "+task); 
      task.initialise(); 
      task.execute(); 
      task.finalise(); 
     } 
     // All tasks performed! Next state. 
     state = flow.get(state); 
     } 
     System.out.println("State: "+state); 
    } 
    } 

    enum State { 
    Start, 
    A(Task.One, Task.Two), 
    B(Task.Two), 
    Finished; 
    Iterable<Task> tasks; 

    State(Task... tasks) { 
     this.tasks = Arrays.asList(tasks); 
    } 
    } 

    enum Task { 
    One { 
     @Override 
     void execute() { 
     } 
    }, 
    Two { 
     @Override 
     void execute() { 
     } 
    }; 

    // Nothing by default. 
    void initialise() { 
    } 

    abstract void execute(); 

    // Nothing by default. 
    void finalise() { 
    } 

    } 

    public static void main(String args[]) { 
    try { 
     new Test().test(); 
    } catch (Throwable t) { 
     t.printStackTrace(System.err); 
    } 
    } 
} 

, который, как мне кажется, демонстрирует разделение контроль потока от выполнения задачи, с которой я пытался справиться.

+0

В принципе, моя задача 'Task' имеет метод инициализации, execute и finalize. Методы initialize и execute возвращают либо EXECUTING, WAITING, FINALIZING, либо COMPLETED состояние, из-за чего вызов будет вызываться next, задача должна быть приостановлена, finalize() для вызова next, или задание, которое будет отмечено, соответственно. Разве это действительно лучшее решение для определения второго перечисления с этими 4 возможными возвращаемыми значениями и обработкой, которые с помощью оператора switch просто делают «если WAITING, state = WAITING, если COMPLETED, state = COMPLETED; ...» Кажется, что отходы ... –

+0

@MarkusA. - Я опубликовал код - возможно, это поможет продемонстрировать, что я имею в виду. – OldCurmudgeon

+0

В этом коде есть действительно интересные идеи! Благодаря! Интересная идея определить метод «выполнить» непосредственно на state-enum и иметь задачи как значения enum, а не классы. Кроме того, я понятия не имел, что в перечислении вы можете определить абстрактный класс и реализовать его одним выстрелом. Интересно.Но похоже, что в коде есть много указаний и обращений, и это довольно долго. Но это определенно полезно увидеть. +1 –

Смежные вопросы