2013-07-23 3 views
5

Java에서 특정 enum 값을 package-private로 표시 할 수 있습니까? 즉, 기본 수정자를 부여 할 수 있습니까?Java에서 열거 형 값의 가시성

배경 (전용 "무엇을 위해?"그렇지 않다면 즉시 첫 코멘트를 선점하기 위해;))

내가 다른 실행-방법과 호출하는 방법을 결정하는 실행 상태와 Task -object가 다음 것. 각각의 실행 메소드는 호출 될 다음 메소드 (기본적으로 상태 머신을 실행하기위한 프레임 워크)의 실행 상태를 리턴합니다.

가능한 모든 실행 상태가 포함되어 있지만 execution-methods로 반환 할 수없는 "보류 중"또는 "실패"와 같은 몇 가지 "패키지 내부"상태가 포함 된 enum이 있습니다.

는 내가 자신의 열거 된 별도의 변수에 이러한 상태를 관리 할 수 ​​알지만, 그것은 두 (적어도) (그리고 아마도 if 주변에 하나의 switch -statement를 회전으로 그 훨씬 덜 깨끗한 코드를 만들 것). 물론 반환 값을 확인할 수도 있지만 처음에는 잘못된 값을 사용할 수도 있습니다.

+3

아니요, 일부 열거 형 상수 및 일부 패키지 전용을 표시 할 수 없습니다. –

+1

이 경우 어쩌면 몇 가지 최종 정적 상수와 그냥 이전 자바 enums, 클래스를 사용할 수 있습니다. – 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 문이 없으며지도 조회 등이 필요하지 않은 경우 .value 필요). 실제로 GWT와 같은 스마트 컴파일러를 사용하면 반환 값은 .value -lookup까지 완전히 제거 (즉, 성능 오버 헤드가 전혀 발생하지 않음) 될 때까지 "인라인"되어야합니다. 이와 또한

, 다른 컨텍스트위한 큰 집단 ENUM 다른 허용 서브 세트의 임의의 수를 정의 할 수있다 : I 쉽게 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 가지 가능한 반환 값을 가진 두 번째 열거 형을 정의하고 "if wait, state = WAITING; if complete, state = COMPLETED;"와 같은 switch 문을 사용하여 처리하는 것이 가장 좋은 해결책입니까? 낭비 ... –

+0

@ MarkusA. - 일부 코드를 게시했습니다. 아마도 그 의미를 입증하는 데 도움이됩니다. – OldCurmudgeon

+0

이 코드에는 정말 멋진 아이디어가 있습니다! 감사! state-enum에 직접 "perform"메소드를 정의하고 태스크가 클래스가 아닌 enum-value가되도록하는 흥미로운 아이디어. 또한, 열거 형에서 추상 클래스를 정의하고이를 한 번에 구현할 수 있다는 것을 알지 못했습니다. 흥미 롭 군.그러나 코드에 많은 간접 참조와 룩업 (look-ups)이 있으며 꽤 길다. 그러나 확실히 보는 것이 유용합니다. +1 –