एनम एक इंटरफ़ेस क्यों लागू करेगा?


जवाबों:


130

एनमों को केवल निष्क्रिय सेट (जैसे रंग) का प्रतिनिधित्व नहीं करना है। वे कार्यक्षमता के साथ और अधिक जटिल वस्तुओं का प्रतिनिधित्व कर सकते हैं, और इसलिए आप इन में और अधिक कार्यक्षमता जोड़ना चाहते हैं - जैसे कि आपके पास इंटरफेस जैसे Printable, Reportableआदि और घटक जो इन का समर्थन करते हैं।


259

यहाँ एक उदाहरण (एक समान / बेहतर एक प्रभावी जावा 2 संस्करण में पाया गया है):

public interface Operator {
    int apply (int a, int b);
}

public enum SimpleOperators implements Operator {
    PLUS { 
        int apply(int a, int b) { return a + b; }
    },
    MINUS { 
        int apply(int a, int b) { return a - b; }
    };
}

public enum ComplexOperators implements Operator {
    // can't think of an example right now :-/
}

अब दोनों सरल + जटिल ऑपरेटरों की सूची प्राप्त करने के लिए:

List<Operator> operators = new ArrayList<Operator>();

operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));

तो यहाँ आप एक्स्टेंसिबल एनमों का अनुकरण करने के लिए एक इंटरफ़ेस का उपयोग करते हैं (जो कि इंटरफ़ेस का उपयोग किए बिना संभव नहीं होगा)।


3
जटिल ऑपरेटर "पॉव" और जैसे हो सकते हैं।
21

2
पहली बार कभी भी उस Enum सिंटैक्स (सदस्यों के बाद घुंघराले ब्रेसिज़ के साथ) को देखकर, और मैं 6 साल से जावा के साथ प्रोग्रामिंग कर रहा हूं। टीआईएल।
जहाराली

23

Comparableउदाहरण के कई लोगों द्वारा दिए यहाँ गलत है, के बाद से Enumपहले से ही लागू है। आप इसे ओवरराइड भी नहीं कर सकते।

एक बेहतर उदाहरण एक इंटरफ़ेस है जो परिभाषित करता है, चलो कहते हैं, एक डेटा प्रकार। आपके पास सरल प्रकारों को लागू करने के लिए एक enum हो सकता है, और जटिल प्रकारों को लागू करने के लिए सामान्य कक्षाएं हैं:

interface DataType {
  // methods here
}

enum SimpleDataType implements DataType {
  INTEGER, STRING;

  // implement methods
}

class IdentifierDataType implements DataType {
  // implement interface and maybe add more specific methods
}

2
हाँ। Enum पहले से ही Comparable इंटरफ़ेस को लागू करता है और ओवरराइड करने की अनुमति नहीं देता है। मैंने enum क्लास के लिए जावा सोर्स कोड देखा और तुलनात्मक कार्यान्वयन नहीं पाया। क्या कोई मुझे बता सकता है कि एक तुलना विधि के अंदर तुलना करने से क्या मिलता है?
एके

2
@ यह ऑर्डिनल्स की तुलना करता है, जिसका अर्थ है कि प्राकृतिक ऑर्डरिंग स्रोत फ़ाइल में क्रमबद्ध हैं।
Jorn

Enum vars अंतिम हैं और इसलिए तुलना == के साथ होती है, है ना?
djangofan

@djangofan हाँ।
Jorn

17

एक मामला है जिसका मैं अक्सर उपयोग करता हूं। मेरे पास IdUtilबहुत सरल Identifiableइंटरफ़ेस को लागू करने वाली वस्तुओं के साथ काम करने के लिए स्थिर तरीकों के साथ एक वर्ग है:

public interface Identifiable<K> {
    K getId();
}


public abstract class IdUtil {

    public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) {
        for (T t : type.getEnumConstants()) {
            if (Util.equals(t.getId(), id)) {
                return t;
            }
        }
        return null;
    }

    public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) {
        List<T> list = new ArrayList<>();
        for (T t : en.getDeclaringClass().getEnumConstants()) {
             if (t.getId().compareTo(en.getId()) < 0) {
                 list.add(t);
            }
        }
        return list;
    }
}

अगर मैं एक Identifiable enum:

    public enum MyEnum implements Identifiable<Integer> {

        FIRST(1), SECOND(2);

        private int id;

        private MyEnum(int id) {
            this.id = id;
        }

        public Integer getId() {
            return id;
        }

    }

तो मैं इसे idइस तरह से प्राप्त कर सकता हूं :

MyEnum e = IdUtil.get(MyEnum.class, 1);

13

चूंकि एनमेस इंटरफेस को लागू कर सकते हैं, उनका उपयोग सिंगलटन पैटर्न के सख्त प्रवर्तन के लिए किया जा सकता है। एक मानक वर्ग को सिंगलटन बनाने की कोशिश कर रहा है ...

  • सार्वजनिक के रूप में निजी तरीकों को उजागर करने के लिए प्रतिबिंब तकनीकों का उपयोग करने की संभावना के लिए
  • अपने सिंगलटन से विरासत में और कुछ के साथ अपने सिंगलटन के तरीकों पर काबू पाने के लिए

एकल के रूप में Enums इन सुरक्षा मुद्दों को रोकने में मदद करते हैं। हो सकता है कि एनमों को कक्षाओं के रूप में कार्य करने और इंटरफेस को लागू करने के लिए यह योगदान करने वाले कारणों में से एक हो। केवल अनुमान है।

अधिक चर्चा के लिए जावा में /programming/427902/java-enum-singleton और सिंगलटन क्लास देखें ।


1
for inheriting from your singleton and overriding your singleton's methods with something else। आप इसे final classरोकने के लिए बस एक का उपयोग कर सकते हैं
Dylanthepiguy

10

यह एक्स्टेंसिबिलिटी के लिए आवश्यक है - यदि कोई आपके द्वारा विकसित एपीआई का उपयोग करता है, तो आपके द्वारा परिभाषित की गई ईनाम स्थिर हैं; उन्हें जोड़ा या संशोधित नहीं किया जा सकता है। हालाँकि, यदि आप इसे इंटरफ़ेस लागू करने देते हैं, तो API का उपयोग करने वाला व्यक्ति उसी इंटरफ़ेस का उपयोग करके अपना स्वयं का एनम विकसित कर सकता है। फिर आप इस एनम को एक एनम मैनेजर के साथ पंजीकृत कर सकते हैं जो मानक इंटरफेस के साथ एनमों को एकत्रित करता है।

संपादित करें: @ हेल्पर विधि का सही उदाहरण है। नए संचालकों को परिभाषित करने वाले अन्य पुस्तकालयों के बारे में सोचें और फिर एक प्रबंधक वर्ग को बताएं कि 'हे, यह बात मौजूद है - इसे पंजीकृत करें'। अन्यथा, आप केवल ऑपरेटर्स को अपने कोड में परिभाषित करने में सक्षम होंगे - कोई एक्स्टेंसिबिलिटी नहीं होगी।


7

Enums केवल भेस में कक्षाएं हैं, इसलिए अधिकांश भाग के लिए, आप एक वर्ग के साथ कुछ भी कर सकते हैं जो आप एक एनम के साथ कर सकते हैं।

मैं एक कारण के बारे में नहीं सोच सकता कि एक एनम एक इंटरफ़ेस को लागू करने में सक्षम नहीं होना चाहिए, उसी समय मैं उनके लिए एक अच्छा कारण भी नहीं सोच सकता।

मैं कहूंगा कि एक बार जब आप इंटरफेस, या विधि जैसी चीज जोड़ना शुरू करते हैं, तो आपको वास्तव में इसके बजाय इसे एक वर्ग बनाने पर विचार करना चाहिए। बेशक, मुझे यकीन है कि गैर-पारंपरिक एनुम चीजों को करने के लिए वैध मामले हैं, और चूंकि सीमा एक कृत्रिम होगी, इसलिए मैं लोगों को यह बताने के पक्ष में हूं कि वे वहां क्या चाहते हैं।


4
"... इसलिए अधिकांश भाग के लिए आप एक वर्ग के साथ कुछ भी कर सकते हैं जो आप एक एनम के साथ कर सकते हैं", फिर भी मैं यह नहीं कह सकता कि मेरी एनम एक अमूर्त वर्ग से विरासत में मिली है। तो हाँ, "सबसे अधिक भाग के लिए" पर जोर दिया।
एडम पार्किं

5
ऐसा इसलिए है क्योंकि enums सभी java.lang.Enum का विस्तार करते हैं, और जावा कक्षाएं केवल एक वर्ग से विस्तारित हो सकती हैं।
टोफूबीर

6

उदाहरण के लिए यदि आपके पास एक लॉगर एनम है। तब आपके पास इंटरफ़ेस में डीबगर, जानकारी, चेतावनी और त्रुटि जैसे लकड़हारा तरीके होने चाहिए। यह आपके कोड को शिथिल करता है।



5

इंटरफ़ेस के साथ एनम का उपयोग करने के लिए मेरे लिए सबसे अच्छा उपयोग केस में से एक है प्रेडिकेट फिल्टर। यह अपाचे संग्रहों की कोमलता की कमी को दूर करने का बहुत ही सुंदर तरीका है (यदि अन्य पुस्तकालयों का उपयोग नहीं किया जा सकता है)।

import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;


public class Test {
    public final static String DEFAULT_COMPONENT = "Default";

    enum FilterTest implements Predicate {
        Active(false) {
            @Override
            boolean eval(Test test) {
                return test.active;
            }
        },
        DefaultComponent(true) {
            @Override
            boolean eval(Test test) {
                return DEFAULT_COMPONENT.equals(test.component);
            }
        }

        ;

        private boolean defaultValue;

        private FilterTest(boolean defautValue) {
            this.defaultValue = defautValue;
        }

        abstract boolean eval(Test test);

        public boolean evaluate(Object o) {
            if (o instanceof Test) {
                return eval((Test)o);
            }
            return defaultValue;
        }

    }

    private boolean active = true;
    private String component = DEFAULT_COMPONENT;

    public static void main(String[] args) {
        Collection<Test> tests = new ArrayList<Test>();
        tests.add(new Test());

        CollectionUtils.filter(tests, FilterTest.Active);
    }
}

5

उपर्युक्त रणनीतियों के बाद का पद पर्याप्त तनाव में नहीं आया, जो कि एनमों का उपयोग करते हुए रणनीति पैटर्न का एक अच्छा हल्का कार्यान्वयन आपको मिलता है:

public enum Strategy {

  A {
    @Override
    void execute() {
      System.out.print("Executing strategy A");
    }
  },

  B {
    @Override
    void execute() {
      System.out.print("Executing strategy B");
    }
  };

  abstract void execute();
}

आप प्रत्येक के लिए एक अलग संकलन इकाई की आवश्यकता के बिना अपनी सभी रणनीतियों को एक ही स्थान पर रख सकते हैं। आपको बस एक अच्छा गतिशील प्रेषण मिलता है:

Strategy.valueOf("A").execute();

जावा लगभग एक अच्छी तरह से लिखी गई भाषा की तरह पढ़ता है!


3

Enums Java Classes की तरह हैं, उनमें कंस्ट्रक्टर, मेथड्स आदि हो सकते हैं, केवल एक चीज जो आप उनके साथ नहीं कर सकते हैं वह है new EnumName()। उदाहरणों को आपके enum घोषणा में पूर्वनिर्धारित किया जाता है।


किस बारे में enum Foo extends SomeOtherClass? तो एक नियमित वर्ग के रूप में एक ही बात नहीं है, वास्तव में, काफी अलग है।
एडम पार्किं

@ एडम: मैं कहूंगा कि जिस तरह से एनमूम्स कक्षाओं से मिलते जुलते हैं, वे उन तरीकों की तुलना में बहुत अधिक हैं, जिनमें वे कक्षाओं से अलग हैं। लेकिन, नहीं, वे समान नहीं हैं।
scottb

यदि आप एक एनम को डिकंपाइल करते हैं, तो आप देखेंगे कि यह एक वर्ग है जो एन्यूमरेशन का विस्तार करता है और "कॉन्स्टेंट" है जो पहले से ही कंस्ट्रक्टर / इनिशियलाइज़ेशन फ़ील्ड में त्वरित है।
कोस्मिन कोस्मिन

3

एक और सकारात्मकता:

public enum ConditionsToBeSatisfied implements Predicate<Number> {
    IS_NOT_NULL(Objects::nonNull, "Item is null"),
    IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"),
    IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative");

    private final Predicate<Number> predicate;
    private final String notSatisfiedLogMessage;

    ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) {
        this.predicate = predicate;
        this.notSatisfiedLogMessage = notSatisfiedLogMessage;
    }

    @Override
    public boolean test(final Number item) {
        final boolean isNotValid = predicate.negate().test(item);

        if (isNotValid) {
            log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);
        }

        return predicate.test(item);
    }
}

और उपयोग:

Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);

3

जार फ़ाइल में स्थिरांक बनाते समय, उपयोगकर्ताओं को एनम मानों का विस्तार करने में अक्सर मदद मिलती है। हमने PropertyFile कुंजियों के लिए enums का उपयोग किया और अटक गए क्योंकि कोई भी नया जोड़ नहीं सकता था! नीचे बहुत बेहतर काम किया होगा।

दिया हुआ:

public interface Color {
  String fetchName();
}

तथा:

public class MarkTest {

  public static void main(String[] args) {
    MarkTest.showColor(Colors.BLUE);
    MarkTest.showColor(MyColors.BROWN);
  }

  private static void showColor(Color c) {
    System.out.println(c.fetchName());
  }
}

एक जार में एक enum हो सकता है:

public enum Colors implements Color {
  BLUE, RED, GREEN;
  @Override
  public String fetchName() {
    return this.name();
  }
}

और एक उपयोगकर्ता अपने रंगों को जोड़ने के लिए इसे बढ़ा सकता है:

public enum MyColors implements Color {
  BROWN, GREEN, YELLOW;
  @Override
  public String fetchName() {
    return this.name();
  }
}

2

यहाँ मेरा कारण है ...

मैंने एक Enum के मानों के साथ JavaFX ComboBox को आबाद किया है। मेरे पास एक इंटरफ़ेस है, पहचान योग्य (एक विधि निर्दिष्ट करना: पहचान करना), जो मुझे यह निर्दिष्ट करने की अनुमति देता है कि कोई भी वस्तु खोज के प्रयोजनों के लिए मेरे आवेदन के लिए खुद को कैसे पहचानती है। यह इंटरफ़ेस मुझे पहचान मैच के लिए किसी भी प्रकार की वस्तुओं (जो भी क्षेत्र वस्तु का उपयोग कर सकता है) की सूचियों को स्कैन करने में सक्षम बनाता है।

मैं अपनी कॉम्बो बॉक्स सूची में एक पहचान मूल्य के लिए एक मैच ढूंढना चाहता हूं। Enum मानों वाले मेरे ComboBox पर इस क्षमता का उपयोग करने के लिए, मुझे अपने Enum में पहचानने योग्य इंटरफ़ेस को लागू करने में सक्षम होना चाहिए (जो कि ऐसा होता है, Enum के मामले में लागू करने के लिए तुच्छ है)।


1

मैंने एक इंटरफ़ेस में एक आंतरिक Enum का उपयोग किया, जिसमें उदाहरण पर नियंत्रण रखने की रणनीति का वर्णन किया गया है (प्रत्येक रणनीति एक सिंगलटन है)।

public interface VectorizeStrategy {

    /**
     * Keep instance control from here.
     * 
     * Concrete classes constructors should be package private.
     */
    enum ConcreteStrategy implements VectorizeStrategy {
        DEFAULT (new VectorizeImpl());

        private final VectorizeStrategy INSTANCE;

        ConcreteStrategy(VectorizeStrategy concreteStrategy) {
            INSTANCE = concreteStrategy;
        }

        @Override
        public VectorImageGridIntersections processImage(MarvinImage img) {
            return INSTANCE.processImage(img);
        }
    }

    /**
     * Should perform edge Detection in order to have lines, that can be vectorized.
     * 
     * @param img An Image suitable for edge detection.
     * 
     * @return the VectorImageGridIntersections representing img's vectors 
     * intersections with the grids.
     */
    VectorImageGridIntersections processImage(MarvinImage img);
}

यह तथ्य कि एनम की रणनीति लागू होती है, एनम वर्ग को अपने संलग्न उदाहरण के लिए प्रॉक्सी के रूप में कार्य करने की अनुमति देना सुविधाजनक है। जो इंटरफ़ेस को भी लागू करता है।

यह एक तरह की रणनीति है।

VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);

यदि यह इंटरफ़ेस लागू नहीं करता था, तो यह था:

VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.