Java中枚举值的可见性

时间:2013-07-23 16:17:37

标签: java enums visibility

是否有可能以某种方式将Java中的某些enum值标记为package-private,即为它们提供默认修饰符?

背景(仅为了抢占其他立即的第一条评论“为什么?”;))

我有一个Task - 具有不同执行方法的对象和一个执行状态,用于决定下一个要调用的方法。每个执行方法都返回下一个要调用的方法的执行状态(基本上是执行状态机的框架)。

我有enum包含所有可能的执行状态,但也包含一些“包内部”状态,如“pending”或“failed”,执行方法不应该返回。 / p>

我知道我可以使用自己的枚举在一个单独的变量中管理这些状态,但是这会使代码变得不那么干净,因为它将单个switch - 语句转换为(至少)两个(并且可能周围的if)。此外,我当然可以只检查返回值,但我甚至不想在第一时间提供错误的值。

2 个答案:

答案 0 :(得分:5)

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

但是,考虑到不同的评论和答案(特别是Marcelo,BlackVegetable和OldCurmudgeon),我提出了以下解决方法:

package-private 枚举包含所有值:

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-statement,没有Map-lookups等,只有{{1}要求)。事实上,使用像GWT这样的智能编译器,返回值应该“内联”到即使.value - 查找被完全删除,即根本没有性能开销。

此外,有了这个,可以为不同的上下文定义一个大的集合枚举的任意数量的不同允许子集:我可以很容易地定义另一个.value,它从{展示一组完全不同的值{1}}。

答案 1 :(得分:1)

你遇到了困难,因为你使用了错误的模式。

您的Task不应该返回下一个州。您应该使用State的矩阵来控制流量。通过这种方式,您的流程不会在任务中纠结,State对流程系统保持私密。

如果您希望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);
    }
  }
}
我认为,这证明了流量控制与我试图解决的任务执行的分离。