2013-07-23 10 views
5

Javaの特定のenumの値を何らかの形でパッケージプライベートとしてマークすることはできますか?つまり、デフォルトの修飾子を指定できますか?Javaのenum値の可視性

背景(のみ「何のために?」そうすぐに最初のコメントを先取りする;))

私が呼び出すためにどの方法を決定し、異なる実行-方法や実行状態とTask -objectを持っています次。実行メソッドのそれぞれは、呼び出される次のメソッド(基本的にステートマシンを実行するためのフレームワーク)の実行状態を返します。

実行可能なすべての実行状態を含むがありますが、実行方法によって返されるべきではない「保留中」または「失敗」のようないくつかの「パッケージ内部」状態も含まれています。

は、私は、独自の列挙と、別の変数にこれらの状態を管理することができ知っているが、それは2つ(少なくとも)(そしておそらくifを囲むに単一switch -statementを回すと、それははるかに少ないクリーンなコードになるだろう)。もちろん、戻り値をチェックすることもできますが、最初は間違った値を返すことさえしません。

+3

いいえ、一部の列挙定数をパブリックに、一部をプライベートにマークすることはできません。 –

+1

この場合は、古いJavaのenumを使うことができます。いくつかの最終静的定数を持つクラスだけです。 – 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; 

これは一般から望ましくない値を隠してしまい、パッケージ内のコーディングとパフォーマンスのオーバーヘッドを同時に最小限に抑えることができます。スイッチやif文、Map-lookupなどがない場合は、.valueが必要です)。実際、GWTのようなスマートなコンパイラでは、戻り値はおそらく.value -lookupが完全に削除される、つまりパフォーマンスオーバーヘッドがまったくない点まで「インライン」になるはずです。

また、異なるコンテキストに対して大きな集合エニュメントの許可された異なるサブセットの任意の数を定義することができます。PackagePrivateEnumから全く異なる値のセットを公開する別のPublicEnum2を簡単に定義できます。

+0

この回答は私のコメントで目指していたものです。 +1 – BlackVegetable

+0

@BlackVegetable :)それは理にかなっています!私は上のリストにあなたを追加しました::) –

1

不適切なパターンを使用しているため、問題が発生しています。

Taskは次の状態に戻ってはなりません。フローを制御するには、Stateの行列を使用する必要があります。このようにして、あなたの流れは仕事の中で絡み合っておらず、Stateはフローシステムにはプライベートなままです。

Taskにフローを制御させたい場合は、フローコントローラに影響を与える何らかのもの(おそらく成功/失敗)を返さなければなりません。彼らは次の状態を定義するべきではありません影響次の状態。

を追加しました

は、ここで私が言いたいのやや不自然な例です。各StateTaskがどのように接続されているかに注目し、フローは各状態遷移を保持するだけの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'は初期化、実行、ファイナライズメソッドを持っています。 initialize-とexecute-methodsは、EXECUTING、WAITING、FINALIZING、またはCOMPLETEDのいずれかの状態を返します。これにより、execute()が次に呼び出され、保留されるタスクはfinalize()またはマークするタスクをそれぞれ完了します。これらの4つの可能な戻り値を持つ2番目の列挙型を定義し、 "WAITING、state = WAITING; COMPLETED、state = COMPLETED;の場合はswitchステートメントで処理するのが、ごみ... –

+0

@マークスA。 - 私はいくつかのコードを掲示しました - おそらく私が意味することを実証するのに役立ちます。 – OldCurmudgeon

+0

このコードには本当にクールなアイデアがあります!ありがとう! state-enumに直接「perform」メソッドを定義し、タスクをクラスではなくenum-valuesにするという興味深い考え方。また、列挙型で抽象クラスを定義し、それを一度に実装することはできません。面白い。しかし、あなたのコードには多くの間接参照やルックアップがあり、それはかなり長いようです。しかし、それは間違いなく見て分かります。 +1 –