8

Javaの特定の値を package-private としてマークするenum、つまりデフォルトの修飾子を与えることは可能ですか?

背景(そうでなければ即時の最初のコメント「何のために?」を先取りするためだけに;))

異なる実行方法を持つTaskオブジェクトと、次に呼び出す方法を決定する実行状態があります。各実行メソッドは、次に呼び出されるメソッドの実行状態を返します (基本的には、ステートマシンを実行するためのフレームワーク)。

考えenumられるすべての実行状態を含む がありますが、「保留中」や「失敗」など、実行メソッドによって返されてはならない「パッケージ内部」の状態もいくつか含まれています。

これらの状態を独自の列挙型を持つ別の変数で管理できることはわかっていますが、単一のswitch-statement を (少なくとも) 2 つ (およびおそらく周囲のif) に変えるため、コードのクリーンさが大幅に低下します。また、もちろん、戻り値を確認することもできますが、そもそも間違った値を使用可能にすることさえしたくありません。

4

2 に答える 2

7

簡単な答えは「いいえ」のようです。

しかし、さまざまなコメントと回答 (特に Marcelo、BlackVegetable、OldCurmudgeon によるもの) を考えて、次の回避策を考え出しました。

package-private列挙にはすべての値が含まれます。

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

2 番目の public enum には public 値のみが含まれ、これらを package-private 値に直接マップします。

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;
    }
}

ここで、パブリック値の 1 つだけを返すことが許可されている関数がある場合、次のように定義します。

public abstract PublicEnum returnSomething();

そして、次の方法でパッケージで使用できます。

PackagePrivateEnum value = returnSomething().value;

これにより、不要な値が公開されないようになり、パッケージ内のコーディングとパフォーマンスのオーバーヘッドが同時に最小限に抑えられると思います (たとえば、switch ステートメントや if ステートメント、Map ルックアップなどは.value必要ありません)。実際、GWT のようなスマート コンパイラを使用すると、戻り値はおそらく "インライン化" されて、.value-lookup も完全に削除されます。つまり、パフォーマンス オーバーヘッドがまったくなくなります。

PublicEnum2また、これにより、さまざまなコンテキストに対して大きな集合列挙型の任意の数の異なる許可されたサブセットを定義することができますPackagePrivateEnum

于 2013-07-23T17:02:41.930 に答える
2

間違ったパターンを使用しているため、問題が発生しています。

あなたTaskの s は次の状態を返すべきではありません。Stateフローを制御するには、s の行列を使用する必要があります。こうすることで、フローがタスク内で絡まることはなく、States はフロー システムに対して非公開のままです。

フローを制御したい場合はTask、フローコントローラーに影響を与えるために何か (おそらく成功/失敗) を返す必要があります。次の状態を定義するのではなく、次の状態に影響を与える必要があります。

追加した

これは、私が言いたいことの少し不自然な例です。Taskがそれぞれに接続され、各状態遷移を保持するだけ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);
    }
  }
}

これは、私が理解しようとしていたタスク実行からのフロー制御の分離を示していると思います。

于 2013-07-23T16:26:38.980 に答える