जवाबों:
एनमों को केवल निष्क्रिय सेट (जैसे रंग) का प्रतिनिधित्व नहीं करना है। वे कार्यक्षमता के साथ और अधिक जटिल वस्तुओं का प्रतिनिधित्व कर सकते हैं, और इसलिए आप इन में और अधिक कार्यक्षमता जोड़ना चाहते हैं - जैसे कि आपके पास इंटरफेस जैसे Printable
, Reportable
आदि और घटक जो इन का समर्थन करते हैं।
यहाँ एक उदाहरण (एक समान / बेहतर एक प्रभावी जावा 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()));
तो यहाँ आप एक्स्टेंसिबल एनमों का अनुकरण करने के लिए एक इंटरफ़ेस का उपयोग करते हैं (जो कि इंटरफ़ेस का उपयोग किए बिना संभव नहीं होगा)।
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
}
एक मामला है जिसका मैं अक्सर उपयोग करता हूं। मेरे पास 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);
चूंकि एनमेस इंटरफेस को लागू कर सकते हैं, उनका उपयोग सिंगलटन पैटर्न के सख्त प्रवर्तन के लिए किया जा सकता है। एक मानक वर्ग को सिंगलटन बनाने की कोशिश कर रहा है ...
एकल के रूप में Enums इन सुरक्षा मुद्दों को रोकने में मदद करते हैं। हो सकता है कि एनमों को कक्षाओं के रूप में कार्य करने और इंटरफेस को लागू करने के लिए यह योगदान करने वाले कारणों में से एक हो। केवल अनुमान है।
अधिक चर्चा के लिए जावा में /programming/427902/java-enum-singleton और सिंगलटन क्लास देखें ।
for inheriting from your singleton and overriding your singleton's methods with something else
। आप इसे final class
रोकने के लिए बस एक का उपयोग कर सकते हैं
यह एक्स्टेंसिबिलिटी के लिए आवश्यक है - यदि कोई आपके द्वारा विकसित एपीआई का उपयोग करता है, तो आपके द्वारा परिभाषित की गई ईनाम स्थिर हैं; उन्हें जोड़ा या संशोधित नहीं किया जा सकता है। हालाँकि, यदि आप इसे इंटरफ़ेस लागू करने देते हैं, तो API का उपयोग करने वाला व्यक्ति उसी इंटरफ़ेस का उपयोग करके अपना स्वयं का एनम विकसित कर सकता है। फिर आप इस एनम को एक एनम मैनेजर के साथ पंजीकृत कर सकते हैं जो मानक इंटरफेस के साथ एनमों को एकत्रित करता है।
संपादित करें: @ हेल्पर विधि का सही उदाहरण है। नए संचालकों को परिभाषित करने वाले अन्य पुस्तकालयों के बारे में सोचें और फिर एक प्रबंधक वर्ग को बताएं कि 'हे, यह बात मौजूद है - इसे पंजीकृत करें'। अन्यथा, आप केवल ऑपरेटर्स को अपने कोड में परिभाषित करने में सक्षम होंगे - कोई एक्स्टेंसिबिलिटी नहीं होगी।
Enums केवल भेस में कक्षाएं हैं, इसलिए अधिकांश भाग के लिए, आप एक वर्ग के साथ कुछ भी कर सकते हैं जो आप एक एनम के साथ कर सकते हैं।
मैं एक कारण के बारे में नहीं सोच सकता कि एक एनम एक इंटरफ़ेस को लागू करने में सक्षम नहीं होना चाहिए, उसी समय मैं उनके लिए एक अच्छा कारण भी नहीं सोच सकता।
मैं कहूंगा कि एक बार जब आप इंटरफेस, या विधि जैसी चीज जोड़ना शुरू करते हैं, तो आपको वास्तव में इसके बजाय इसे एक वर्ग बनाने पर विचार करना चाहिए। बेशक, मुझे यकीन है कि गैर-पारंपरिक एनुम चीजों को करने के लिए वैध मामले हैं, और चूंकि सीमा एक कृत्रिम होगी, इसलिए मैं लोगों को यह बताने के पक्ष में हूं कि वे वहां क्या चाहते हैं।
इसके लिए सबसे आम उपयोग दो दुश्मनी के मूल्यों को एक समूह में विलय करना और उनके साथ समान व्यवहार करना होगा। उदाहरण के लिए, देखें कि फ्रूट्स और वेजटेबल्स कैसे जुड़ें ।
इंटरफ़ेस के साथ एनम का उपयोग करने के लिए मेरे लिए सबसे अच्छा उपयोग केस में से एक है प्रेडिकेट फिल्टर। यह अपाचे संग्रहों की कोमलता की कमी को दूर करने का बहुत ही सुंदर तरीका है (यदि अन्य पुस्तकालयों का उपयोग नहीं किया जा सकता है)।
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);
}
}
उपर्युक्त रणनीतियों के बाद का पद पर्याप्त तनाव में नहीं आया, जो कि एनमों का उपयोग करते हुए रणनीति पैटर्न का एक अच्छा हल्का कार्यान्वयन आपको मिलता है:
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();
जावा लगभग एक अच्छी तरह से लिखी गई भाषा की तरह पढ़ता है!
Enums Java Classes की तरह हैं, उनमें कंस्ट्रक्टर, मेथड्स आदि हो सकते हैं, केवल एक चीज जो आप उनके साथ नहीं कर सकते हैं वह है new EnumName()
। उदाहरणों को आपके enum घोषणा में पूर्वनिर्धारित किया जाता है।
enum Foo extends SomeOtherClass
? तो एक नियमित वर्ग के रूप में एक ही बात नहीं है, वास्तव में, काफी अलग है।
एक और सकारात्मकता:
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);
जार फ़ाइल में स्थिरांक बनाते समय, उपयोगकर्ताओं को एनम मानों का विस्तार करने में अक्सर मदद मिलती है। हमने 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();
}
}
यहाँ मेरा कारण है ...
मैंने एक Enum के मानों के साथ JavaFX ComboBox को आबाद किया है। मेरे पास एक इंटरफ़ेस है, पहचान योग्य (एक विधि निर्दिष्ट करना: पहचान करना), जो मुझे यह निर्दिष्ट करने की अनुमति देता है कि कोई भी वस्तु खोज के प्रयोजनों के लिए मेरे आवेदन के लिए खुद को कैसे पहचानती है। यह इंटरफ़ेस मुझे पहचान मैच के लिए किसी भी प्रकार की वस्तुओं (जो भी क्षेत्र वस्तु का उपयोग कर सकता है) की सूचियों को स्कैन करने में सक्षम बनाता है।
मैं अपनी कॉम्बो बॉक्स सूची में एक पहचान मूल्य के लिए एक मैच ढूंढना चाहता हूं। Enum मानों वाले मेरे ComboBox पर इस क्षमता का उपयोग करने के लिए, मुझे अपने Enum में पहचानने योग्य इंटरफ़ेस को लागू करने में सक्षम होना चाहिए (जो कि ऐसा होता है, Enum के मामले में लागू करने के लिए तुच्छ है)।
मैंने एक इंटरफ़ेस में एक आंतरिक 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);