8

Is it possible to somehow mark certain enum values in Java as package-private, i.e. give them the default modifier?

Background (only to preempt the otherwise immediate first comment "What for?" ;) )

I have a Task-object with different execution-methods and an execution-state that decides which method to call next. Each one of the execution-methods returns the execution-state of the next method to be called (basically a framework for executing a state-machine).

I have an enum that contains all possible execution-states, but also contains a few "package-internal" states like "pending" or "failed" that should not be returnable by the execution-methods.

I know I could manage these states in a separate variable with its own enum, but that would make the code a lot less clean as it turns a single switch-statement into (at least) two (and possibly a surrounding if). Also, I could, of course, just check the return value, but I'd rather not even make wrong ones available in the first place.

4

2 回答 2

7

听起来简单的答案是“不”。

但是,考虑到不同的评论和答案(尤其是 Marcelo、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 语句,没有 Map-lookups 等,只是.value必需的)。事实上,使用像 GWT 这样的智能编译器,返回值可能应该被“内联”到甚至.value完全删除 -lookup 的程度,即根本没有性能开销。

此外,有了这个,可以为不同的上下文定义任意数量的大集合枚举的不同允许子集:我可以轻松定义另一个PublicEnum2公开一组完全不同的值的PackagePrivateEnum.

于 2013-07-23T17:02:41.930 回答
2

您遇到困难是因为您使用了错误的模式。

Task的 s 不应该返回下一个状态。您应该使用States 的矩阵来控制流量。这样,您的流程就不会在任务中纠缠不清,并且States 对流程系统保持私有。

如果你想让你Task控制流量,他们应该返回一些东西(可能是成功/失败)来影响流量控制器。他们不应该定义下一个状态,他们应该影响下一个状态。

添加

这是我的意思的一个稍微做作的例子。请注意Tasks 是如何附加到每个上State的,并且流程是由Map仅保存每个状态转换的 a 控制的。

我已经做出了象征性的努力来匹配您的返回结果,但我怀疑这会使事情变得过于复杂,一旦您接受了流程与状态的分离,您就会意识到我要解释的内容。

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 回答