2013-07-23 10 views
5

क्या किसी भी तरह जावा में कुछ enum मानों को पैकेज-प्राइवेट के रूप में चिह्नित करना संभव है, यानी उन्हें डिफ़ॉल्ट संशोधक दें?जावा में enum मानों की दृश्यता

पृष्ठभूमि (केवल "क्या के लिए?" अन्यथा तत्काल पहली टिप्पणी जगह ले लेना करने के लिए;))

मैं अलग निष्पादन-तरीकों और किसी निष्पादन-राज्य फैसला करता है कि जो विधि कॉल करने के साथ एक Task -object है आगामी। निष्पादन-विधियों में से प्रत्येक एक को अगली विधि के निष्पादन-स्थिति को वापस करने के लिए देता है (मूल रूप से राज्य-मशीन निष्पादित करने के लिए एक ढांचा)।

मेरे पास enum है जिसमें सभी संभावित निष्पादन-राज्य शामिल हैं, लेकिन इसमें "लंबित" या "असफल" जैसे कुछ "पैकेज-आंतरिक" राज्य भी शामिल हैं जिन्हें निष्पादन-विधियों द्वारा वापस करने योग्य नहीं होना चाहिए।

मुझे लगता है मैं अपने आप ही enum के साथ एक अलग चर में इन राज्यों का प्रबंधन कर सकता है, लेकिन के रूप में यह में (कम से कम) दो (और संभवतः एक आसपास के if एक भी switch -statement चला है कि कोड में बहुत कम स्वच्छ बनाना होगा)। इसके अलावा, मैं निश्चित रूप से वापसी मूल्य की जांच कर सकता हूं, लेकिन मैं पहले भी गलत जगहों को उपलब्ध नहीं कराऊंगा।

+3

नहीं, आप कुछ enum स्थिरांक सार्वजनिक और कुछ पैकेज-निजी चिह्नित नहीं कर सकते हैं। –

+1

इस मामले में शायद आप पुराने जावा एनम्स का उपयोग कर सकते हैं, केवल कुछ वर्ग स्थिर स्थिर स्थिरांक वाले वर्ग। – Marcelo

+0

वास्तव में, आप उन्हें कुछ भी चिह्नित नहीं कर सकते हैं। वे 'सार्वजनिक' हैं और यही वह है। –

उत्तर

5

सरल उत्तर की तरह लगता है "नहीं।"

लेकिन, विभिन्न टिप्पणियों और जवाब (विशेष रूप से मार्सेलो, BlackVegetable और OldCurmudgeon द्वारा) के बारे में सोच, मैं निम्नलिखित तरीके को साथ आ गए हैं:

एक पैकेज-निजी enum सभी मान हैं:

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

एक दूसरा सार्वजनिक enum केवल सार्वजनिक मान हैं, और सीधे पैकेज-निजी लोगों के लिए इन मानचित्रों:

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-statement, कोई मैप-लुकअप आदि नहीं, केवल .value आवश्यक)। वास्तव में, जीडब्ल्यूटी जैसे स्मार्ट कंपाइलर के साथ, रिटर्न-वैल्यू को शायद इस बिंदु पर "रेखांकित" होना चाहिए कि .value -lookup पूरी तरह से हटा दिया गया है, यानी कोई प्रदर्शन-ओवरहेड बिल्कुल नहीं है।

इसके अलावा, इस के साथ, यह विभिन्न संदर्भों के लिए एक बड़ा सामूहिक enum के विभिन्न अनुमति सबसेट का एक मनमाना संख्या परिभाषित करना संभव है: मैं आसानी से एक और PublicEnum2 कि PackagePrivateEnum से मानों का एक बिल्कुल अलग सेट को उजागर करता है निर्धारित कर सकते हैं।

+0

यह उत्तर वह था जो मैं अपनी टिप्पणी में लक्षित कर रहा था। +1 – BlackVegetable

+0

@ ब्लैकवेजटेबल :) अब यह समझ में आता है! मैंने आपको सूची में शीर्ष पर जोड़ा ... :) –

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

जो, मुझे लगता है, यह दर्शाता है की जुदाई कार्य निष्पादन से प्रवाह नियंत्रण मैं पार करने की कोशिश कर रहा था।

+0

असल में, मेरे 'कार्य' में प्रारंभिक- एक निष्पादन- और अंतिम रूप-विधि है। प्रारंभिक- और निष्पादन-विधियां या तो एक निष्पादन, एक प्रतीक्षा, एक अंतिमकरण, या एक पूर्ण राज्य लौटाती हैं, जो निष्पादित() को अगली कहलाती है, कार्य को पकड़ने के लिए, अंतिम() को अंतिम रूप देने के लिए अंतिम रूप दिया जाएगा, या कार्य क्रमशः पूरा किया जाना है। क्या यह वास्तव में सबसे अच्छा समाधान है कि इन 4 संभावित वापसी मूल्यों के साथ एक दूसरा enum परिभाषित करने के लिए और एक स्विच स्टेटमेंट के साथ प्रोसेसिंग के साथ बस "अगर प्रतीक्षा, राज्य = प्रतीक्षा; यदि पूर्ण हो, राज्य = पूर्ण हो गया ..." जैसा लगता है अपशिष्ट ... –

+0

@ मार्कस ए। - मैंने कुछ कोड पोस्ट किया है - शायद यह मेरा मतलब बताएगा कि मेरा क्या मतलब है। – OldCurmudgeon

+0

इस कोड में कुछ वाकई अच्छे विचार हैं! धन्यवाद! राज्य-enum पर सीधे "प्रदर्शन" विधि को परिभाषित करने और कक्षाओं के बजाय कार्य enum-values ​​होने के लिए दिलचस्प विचार है। साथ ही, मुझे नहीं पता था कि, एक enum में, आप एक अमूर्त वर्ग को परिभाषित कर सकते हैं और इसे एक शॉट में कार्यान्वित कर सकते हैं। दिलचस्प।लेकिन ऐसा लगता है कि आपके कोड में बहुत सारे संकेत और लुक-अप हैं और यह काफी लंबा है। लेकिन यह देखना निश्चित रूप से उपयोगी है। +1 –

संबंधित मुद्दे