क्या एक स्विच स्टेटमेंट में इंस्टोफ़ ऑपरेटर का उपयोग करना संभव है?


267

मेरे पास instanceofऑब्जेक्ट के लिए स्विच केस का उपयोग करने का प्रश्न है :

उदाहरण के लिए: मेरी समस्या को जावा में पुन: प्रस्तुत किया जा सकता है:

if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():

इसका उपयोग करके कैसे लागू किया जाएगा switch...case?


6
यदि आपको वास्तव में लगता है कि आपको एक स्विच की आवश्यकता है तो आप कक्षा के नाम को एक int पर रख सकते हैं और इसका उपयोग कर सकते हैं, हालांकि संभावित संघर्ष के लिए बाहर देख सकते हैं। उत्तर के बजाय टिप्पणी के रूप में जोड़ना क्योंकि मुझे इस विचार का उपयोग पसंद नहीं है। हो सकता है कि आप वास्तव में क्या जरूरत है आगंतुक पैटर्न है।
विक्रिक

1
जावा 7 के रूप में आप भी इस तरह के हैश संघर्ष से बचने के लिए पूरी तरह से योग्य वर्ग के नाम पर स्विच कर सकते हैं जैसा कि @vickirk ने बताया, लेकिन यह अभी भी बदसूरत है।
मित्जा

जवाबों:


225

यह एक विशिष्ट परिदृश्य है जहां उप-प्रकार बहुरूपता मदद करता है। निम्न कार्य करें

interface I {
  void do();
}

class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }

तो आप बस do()पर कॉल कर सकते हैं this

आप बदलने के लिए स्वतंत्र नहीं हैं, तो A, Bहै, और C, आप एक ही प्राप्त करने के लिए आगंतुक पैटर्न लागू हो सकते हैं।


33
विज़िटर पैटर्न का मतलब है कि ए, बी और सी को एक अमूर्त विधि के साथ एक इंटरफ़ेस लागू करना होगा जो विज़िटर को इनपुट पैरामीटर के रूप में लेता है, क्या होगा यदि आप ए, बी, सी को नहीं बदल सकते हैं और उनमें से कोई भी उस इंटरफ़ेस को लागू नहीं करता है?
Thermz

21
विज़िटर पैटर्न के बारे में अंतिम टिप्पणी गलत है। आपको अभी भी ए, बी और सी को एक इंटरफ़ेस लागू करना होगा।
बेन थर्ले

10
अफसोस की बात है कि यह काम नहीं करता है अगर () - कोड को मेजबान के पर्यावरण की आवश्यकता होती है (यानी कि चर में मौजूद नहीं है () ही)।
मफू

2
@ मफू ओपी का प्रश्न टाइप आधारित प्रेषण के बारे में था। यदि आपकी समस्या को दूर करने के लिए आपके do () विधि को अधिक इनपुट की आवश्यकता है, तो यहां चर्चा किए गए प्रश्न के दायरे से बाहर IMHO है।
jmg

3
यह उत्तर मानता है कि आप ए, बी, सी कक्षाओं को संशोधित कर सकते हैं, जबकि मुझे लगता है कि बिंदु यह है कि ए, बी, सी को संशोधित किए बिना कैसे करें क्योंकि वे तीसरे भाग के पुस्तकालय में हो सकते हैं
क्लाउडी_विदर

96

यदि आप बिल्कुल किसी इंटरफ़ेस में कोड नहीं कर सकते हैं, तो आप एक मध्यस्थ के रूप में एनम का उपयोग कर सकते हैं:

public A() {

    CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName());
    switch (z) {
    case A:
        doA();
        break;
    case B:
        doB();
        break;
    case C:
        doC();
        break;
    }
}


enum CLAZZ {
    A,B,C;

}

thx, मुझे भी कुछ परिवर्तन करने थे: 1) कक्षा संदर्भ के साथ प्रत्येक एनुम आईडी को इनिशियलाइज़ करें; 2) एनाम आईडी .toString () के साथ वर्ग सरल नाम का दावा करें; 3) एनम आईडी प्रति संग्रहीत वर्ग संदर्भ के माध्यम से एनम खोजें। मुझे लगता है कि यह तब भी सुरक्षित है।
कुंभ राशि

अगर यह .getClass ()। getSimpleName () CLAZZ के मान से मेल नहीं खाता है तो यह एक अपवाद को फेंक देता है ... एक कोशिश करने वाले को पकड़ने वाले ब्लॉक के साथ घेरना बेहतर होता है और अपवाद को "डिफ़ॉल्ट" या "अन्य" विकल्प के रूप में माना जाएगा स्विच
टेट्री

40

बस एक मानचित्र बनाएं जहां वर्ग कुंजी और कार्यक्षमता है, यानी लैम्ब्डा या इसी तरह का, मूल्य है।

Map<Class,Runnable> doByClass = new HashMap<>();
doByClass.put(Foo.class, () -> doAClosure(this));
doByClass.put(Bar.class, this::doBMethod);
doByClass.put(Baz.class, new MyCRunnable());

// बेशक, इसे केवल एक बार प्रारंभ करने के लिए रिफ्लेक्टर करें

doByClass.get(getClass()).run();

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


3
सबसे अच्छा समाधान imho, विशेष रूप से क्योंकि यह आसान रिफैक्टिंग की अनुमति देता है।
फिएटिरा

2
इस समाधान के लिए नकारात्मक पक्ष यह है कि यह लैम्ब्डा में स्थानीय (विधि) चर का उपयोग नहीं कर सकता (यह मानते हुए कि निश्चित रूप से आवश्यक हो सकता है)।
२१:

1
@zapatero आप केवल रननेबल के बजाय फ़ंक्शन में बदल सकते हैं, उदाहरण को पैरामीटर के रूप में पास कर सकते हैं, फिर जरूरत पड़ने पर इसे डाल सकते हैं
22

upvoted; यह उन कुछ उत्तरों में से एक है जो वास्तव में ओपी को वह करने में मदद करता है जो वह पूछ रहा है (और हाँ, यह अक्सर कोड को रिफ्लेक्टर करना संभव होता है instanceof, और नहीं, मेरा परिदृश्य दुर्भाग्य से उन लोगों में से एक नहीं है जो आसानी से फिट हो जाते हैं उस बॉक्स ...)
प्रति लंडबर्ग

@ सर्जियोगुटियरेज़ थैंक्स। खैर, इस पैटर्न को केवल एक बाहरी पुस्तकालय के साथ की आवश्यकता होनी चाहिए। और फिर भी आप इसके बजाय एक एडाप्टर कार्यान्वयन के साथ एक इंटरफ़ेस बना सकते हैं, लेकिन यह उपयोगी है जहां आप व्यवहार DIFF चाहते हैं, इसलिए बोलने के लिए, और अधिक स्पष्ट होने के लिए। धाराप्रवाह बनाम एनोटेशन एपीआई रूटिंग I के समान।
नोवेटाटा

36

अगर कोई इसे पढ़ लेगा तो बस:

जावा में सबसे अच्छा समाधान है:

public enum Action { 
    a{
        void doAction(...){
            // some code
        }

    }, 
    b{
        void doAction(...){
            // some code
        }

    }, 
    c{
        void doAction(...){
            // some code
        }

    };

    abstract void doAction (...);
}

ऐसे पैटर्न के महान लाभ हैं:

  1. आप बस इसे पसंद करते हैं (कोई स्विच नहीं):

    void someFunction ( Action action ) {
        action.doAction(...);   
    }
  2. यदि आप "d" नामक नया एक्शन जोड़ते हैं, तो आप जरूरी doAction (...) विधि का अनुकरण करेंगे

नोट: यह पैटर्न जोशुआ के बलोच में "प्रभावी जावा (द्वितीय संस्करण)" में वर्णित है


1
अच्छा! क्या @Overrideप्रत्येक कार्यान्वयन के ऊपर आवश्यक है doAction()?
mateuscb

9
यह "BEST" समाधान कैसे है? आप कैसे तय करेंगे कि किसका actionउपयोग करना है? एक बाहरी उदाहरण-कैस्केड द्वारा जो someFunction()सही के साथ कॉल करता है action? यह सिर्फ अप्रत्यक्ष के एक और स्तर को जोड़ता है।
प्योरस्पीडर

1
नहीं, यह स्वचालित रूप से रनटाइम पर किया जाएगा। यदि आप कुछ फंक्शन (Action.a) कहते हैं तो a.doAction कहलाएगा।
se.solovyev

11
मुझे यह समझ में नहीं आता है। आपको कैसे पता चलेगा कि किस एनम का उपयोग करना है? जैसा कि @PureSpider ने कहा, ऐसा लगता है कि काम करने का सिर्फ एक और स्तर है।
जेम्स मैन्स

2
यह बहुत दुख की बात है कि आपने एक पूर्ण उदाहरण की पेशकश नहीं की , उदाहरण के लिए इस एनम के किसी भी वर्ग-उदाहरण, बी या सी को कैसे मैप करें। मैं इस Enum को उदाहरण देने की कोशिश करूँगा।
टॉम

21

आप नहीं कर सकते। इस switchकथन में केवल वे कथन हो सकते हैं caseजो समकालिक स्थिरांक हैं और जो पूर्णांक (जावा 6 तक और जावा 7 में एक स्ट्रिंग) का मूल्यांकन करते हैं।

आप जो देख रहे हैं उसे कार्यात्मक प्रोग्रामिंग में "पैटर्न मिलान" कहा जाता है।

जावा में टालना भी देखें


1
नहीं, अधिकांश कार्यात्मक भाषाओं में आप केवल कंस्ट्रक्टरों के प्रकारों पर मिलान नहीं कर सकते। एमएल और हास्केल में यह कम से कम सच है। Scala और OCaml में यह संभव है, लेकिन पैटर्न मिलान का विशिष्ट अनुप्रयोग नहीं है।
jmg

ज़रूर, लेकिन निर्माणकर्ताओं के खिलाफ जाँच ऊपर वर्णित परिदृश्य के लिए "समतुल्य" होगी।
कार्लो वी। डंगो

1
कुछ मामलों में, लेकिन सामान्य रूप से नहीं।
jmg

स्विच भी एनम का समर्थन कर सकते हैं।
सुलैमान उको

"आप नहीं कर सकते" एक अलग भाषा को देखो शायद ही कभी एक उपयोगी उत्तर है।
एल। ब्लैंक

17

जैसा कि शीर्ष उत्तरों में चर्चा की गई है, पारंपरिक ओओपी दृष्टिकोण स्विच के बजाय बहुरूपता का उपयोग करना है। इस ट्रिक के लिए एक अच्छी तरह से प्रलेखित रीफैक्टरिंग पैटर्न है: पोलीमिशल को पॉलीमोर्फिज़्म के साथ बदलें । जब भी मैं इस दृष्टिकोण के लिए पहुंचता हूं, मुझे डिफ़ॉल्ट व्यवहार प्रदान करने के लिए एक अशक्त वस्तु को लागू करना भी पसंद है ।

जावा 8 से शुरू करते हुए, हम लैम्बदास और जेनेरिक का उपयोग कर सकते हैं, ताकि हमें कुछ कार्यात्मक प्रोग्रामर मिल सकें: पैटर्न मिलान। यह एक मुख्य भाषा विशेषता नहीं है, लेकिन जावलासंग पुस्तकालय एक कार्यान्वयन प्रदान करता है। जावदोक से उदाहरण :

Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1

यह जावा दुनिया में सबसे प्राकृतिक प्रतिमान नहीं है इसलिए सावधानी के साथ इसका उपयोग करें। जबकि जेनेरिक विधियां आपको मिलान किए गए मान को टाइपकास्ट करने से बचाएंगी, हम उदाहरण के लिए स्काला के केस क्लासेस के साथ मिलान किए गए ऑब्जेक्ट को विघटित करने का एक मानक तरीका गायब कर रहे हैं ।


9

मुझे पता है कि यह बहुत देर से है लेकिन भविष्य के पाठकों के लिए ...

उपरोक्त दृष्टिकोणों से सावधान रहें जो केवल A , B , C ... के वर्ग के नाम पर आधारित हैं :

जब तक आप गारंटी नहीं दे सकते कि , बी , सी ... (सभी उपवर्ग या के कार्यान्वयनकर्ता) बेस ) कर रहे हैं अंतिम की तो उपवर्गों एक , बी , सी ... के साथ पेश नहीं किया जाएगा।

भले ही, अगर, फारस, फारस .. दृष्टिकोण बड़ी संख्या में उपवर्गों / कार्यान्वयनकर्ताओं के लिए धीमा है, तो यह अधिक सटीक है।


वास्तव में, आपको कभी भी बहुरूपता (उर्फ ओओपी) का उपयोग नहीं करना चाहिए
Val

8

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

public enum MyEnum {
   A(A.class.getName()), 
   B(B.class.getName()),
   C(C.class.getName());

private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;

MyEnum (String refClassname) {
    this.refClassname = refClassname;
}

static {
    Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
        map.put(instance.refClassname, instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
}

public static MyEnum get(String name) {
    return ENUM_MAP.get(name);
 }
}

इसके साथ स्विच स्टेटमेंट का उपयोग इस तरह संभव है

MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
    ... // it's A class
case B:
    ... // it's B class
case C:
    ... // it's C class
}

मेरा मानना ​​है कि जब तक जेईपी अंक 76२१३० is६ पूरी तरह से लागू नहीं हो जाता है, तब तक यह सबसे साफ तरीका है कि लक्ष्य वर्ग को संशोधित किए बिना, प्रकार के आधार पर एक स्विच स्टेटमेंट प्राप्त करें।
ऋक शहाफ


5

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

this.do()

पहले एक बेस क्लास स्थापित करना:

abstract class Base {
   abstract void do();
   ...
}

जो के लिए आधार वर्ग है A, Bऔर C:

class A extends Base {
    void do() { this.doA() }
}

class B extends Base {
    void do() { this.doB() }
}

class C extends Base {
    void do() { this.doC() }
}

@jmg सुगरजेस ( stackoverflow.com/questions/5579309/switch-instanceof/… ) एक सार आधार वर्ग के बजाय एक अंतरफलक का उपयोग कर। वह कुछ सर्कसमेण्ट्स में श्रेष्ठ हो सकता है।
राेयदावल

5

यह तेजी से काम करेगा और मामले में समर्पण करेगा
- आपके पास अपेक्षाकृत कई 'मामले' हैं
- प्रक्रिया को संवेदनशील संवेदनशील संदर्भ में निष्पादित किया जाता है

public <T> T process(Object model) {
    switch (model.getClass().getSimpleName()) {
        case "Trade":
            return processTrade();
        case "InsuranceTransaction":
            return processInsuranceTransaction();
        case "CashTransaction":
            return processCashTransaction();
        case "CardTransaction":
            return processCardTransaction();
        case "TransferTransaction":
            return processTransferTransaction();
        case "ClientAccount":
            return processAccount();
        ...
        default:
            throw new IllegalArgumentException(model.getClass().getSimpleName());
    }
}

1
यह केवल एक उदाहरण के रूप में नहीं है, क्योंकि यह केवल तभी काम करता है जब कार्यान्वयन वर्ग को स्विच करने के लिए उपयोग किया जाता है, लेकिन यह इंटरफेस / एब्स्ट्रैक्टक्लास /
सुपरक्लासेस के

हाँ, यह नहीं है
माइक

प्रयास के लिए, लेकिन @ जीवनरक्षक की टिप्पणी से अलग, आप उन प्रकारों को भी याद करते हैं जो आपके पास सामान्य रूप से हैं, क्योंकि यह उत्तर वर्ग संदर्भों के बजाय हार्डकोड स्ट्रिंग्स का उपयोग करता है। यह एक टाइपो बनाने के लिए, खासकर यदि आप पूर्ण विहित नाम के साथ इस कार्यक्षमता बढ़ाने के लिए करता है, तो यहां अलग पैकेज names.Edit साथ वर्ग नाम पर कोई भी ओवरलैप था आवश्यकता होगी काफी आसान है: तय टाइपो (जो थोड़े मेरी बात साबित होता है)
रिक Schaaf

4

आप केवल एक बाइट, शॉर्ट, चार, इंट, स्ट्रिंग और एनुमरेटेड प्रकारों के साथ काम नहीं कर सकते (और आदिमों के ऑब्जेक्ट संस्करण, यह आपके जावा संस्करण पर भी निर्भर करता है, स्ट्रिंग्स को switchजावा 7 में एड किया जा सकता है )


आप जावा 6 में स्ट्रिंग्स पर स्विच नहीं कर सकते। और आप "आदिम के ऑब्जेक्ट संस्करणों" पर स्विच नहीं कर सकते।
लुकास ईडर

@Bozho मैंने कहा कि यह आपके जावा संस्करण पर निर्भर करता है, जावा 7 में आप स्ट्रिंग्स पर स्विच कर सकते हैं।
Tnem

@ लुकास ईडर आपके जावा स्पेक्स की जांच कर सकता है
Tnem

4

मुझे व्यक्तिगत रूप से निम्नलिखित जावा 1.8 कोड पसंद है:

    mySwitch("YY")
            .myCase("AA", (o) -> {
                System.out.println(o+"aa");
            })
            .myCase("BB", (o) -> {
                System.out.println(o+"bb");
            })
            .myCase("YY", (o) -> {
                System.out.println(o+"yy");
            })
            .myCase("ZZ", (o) -> {
                System.out.println(o+"zz");
            });

उत्पादन होगा:

YYyy

नमूना कोड स्ट्रिंग्स का उपयोग करता है लेकिन आप क्लास सहित किसी भी ऑब्जेक्ट प्रकार का उपयोग कर सकते हैं। जैसे.myCase(this.getClass(), (o) -> ...

निम्नलिखित स्निपेट की आवश्यकता है:

public Case mySwitch(Object reference) {
    return new Case(reference);
}

public class Case {

    private Object reference;

    public Case(Object reference) {
        this.reference = reference;
    }

    public Case myCase(Object b, OnMatchDo task) {
        if (reference.equals(b)) {
            task.task(reference);
        }
        return this;
    }
}

public interface OnMatchDo {

    public void task(Object o);
}

4

जावा अब आपको ओपी के तरीके से स्विच करने की अनुमति देता है। वे इसे स्विच के लिए पैटर्न मिलान कहते हैं । यह वर्तमान में ड्राफ्ट के तहत है, लेकिन यह देखते हुए कि हाल ही में वे स्विच में कितना काम कर रहे हैं, मुझे लगता है कि यह गुजर जाएगा। JEP में दिया गया उदाहरण है

String formatted;
switch (obj) {
    case Integer i: formatted = String.format("int %d", i); break;
    case Byte b:    formatted = String.format("byte %d", b); break;
    case Long l:    formatted = String.format("long %d", l); break;
    case Double d:  formatted = String.format("double %f", d); break;
    case String s:  formatted = String.format("String %s", s); break
    default:        formatted = obj.toString();
}  

या उनके लैम्ब्डा सिंटैक्स का उपयोग करके और मान लौटाते हुए

String formatted = 
    switch (obj) {
        case Integer i -> String.format("int %d", i)
        case Byte b    -> String.format("byte %d", b);
        case Long l    -> String.format("long %d", l); 
        case Double d  -> String.format("double %f", d); 
        case String s  -> String.format("String %s", s); 
        default        -> obj.toString();
    };

किसी भी तरह से वे स्विच के साथ शांत सामान कर रहे हैं।


3

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

मेरे लिए, स्विच स्टेटमेंट में लिखित तर्क का होना आवश्यक है, वस्तु का नहीं। यह मेरा समाधान था:

ClassA, ClassB, and ClassC implement CommonClass

इंटरफेस:

public interface CommonClass {
   MyEnum getEnumType();
}

enum:

public enum MyEnum {
  ClassA(0), ClassB(1), ClassC(2);

  private int value;

  private MyEnum(final int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }

impl:

...
  switch(obj.getEnumType())
  {
    case MyEnum.ClassA:
      ClassA classA = (ClassA) obj;
    break;

    case MyEnum.ClassB:
      ClassB classB = (ClassB) obj;
    break;

    case MyEnum.ClassC:
      ClassC classC = (ClassC) obj;
    break;
  }
...

यदि आप जावा 7 पर हैं, तो आप एनम के लिए स्ट्रिंग मान रख सकते हैं और स्विच केस ब्लॉक अभी भी काम करेगा।


valueआप स्थिरांक सीधे उपयोग कर सकते हैं (जैसा कि आप करते हैं) - क्षेत्र बेमानी है अगर आप केवल enum स्थिरांक भेद करने के लिए चाहते हैं।
user905686

2

इस बारे में कैसा है ?

switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}

3
यह इंगित करना चाहिए कि यह केवल जावा 7 पर काम करता है। और आपको यह this.getSimpleName()सुनिश्चित करने के लिए कॉल नहीं करना है कि पोस्टर जेएस के साथ भ्रमित है (हाँ, वह कंसोल का उपयोग कर रहा है, हे)।
pablisco

5
इससे सोर्स कोड रेफरेंशियल ट्रांसपेरेंसी के गिरने की समस्या है। यही है, आपका आईडीई संदर्भ अखंडता को नियंत्रित करने में सक्षम नहीं होगा। मान लीजिए आप अपना नाम बदलना चाहते हैं। प्रतिबिंब बुराई है।
वैल

1
महान विचार नहीं है। यदि आपके पास कई क्लास लोडर हैं, तो क्लास के नाम अद्वितीय नहीं हैं।
डोरैडस

ब्रेक जब यह कोड संपीड़न (→ ProGuard) की बात आती है
मथायस Ronge

1

मुझे लगता है कि स्विच स्टेटमेंट का उपयोग करने के कारण हैं। यदि आप शायद xText द्वारा उत्पन्न कोड का उपयोग कर रहे हैं। या अन्य प्रकार की ईएमएफ उत्पन्न कक्षाएं।

instance.getClass().getName();

कक्षा कार्यान्वयन नाम का एक स्ट्रिंग देता है। यानी: org.eclipse.emf.ecore.util.EcoreUtil

instance.getClass().getSimpleName();

साधारण रीपेनेशन लौटाता है: EcoreUtil


आप में इसका इस्तेमाल नहीं कर सकते हैं switchके रूप में caseशर्त है क्योंकि यह निरंतर मूल्य नहीं है
बी गैंगस्टर

1

यदि आपको "यह" ऑब्जेक्ट के वर्ग प्रकार को "स्विच" करने की आवश्यकता है, तो यह उत्तर सबसे अच्छा है https://stackoverflow.com/a/5579385/2078368

लेकिन अगर आपको किसी अन्य चर पर "स्विच" लगाने की आवश्यकता है। मैं एक और उपाय सुझाऊंगा। निम्नलिखित इंटरफ़ेस को परिभाषित करें:

public interface ClassTypeInterface {
    public String getType();
}

इस इंटरफ़ेस को उस हर वर्ग में लागू करें जिसे आप "स्विच" करना चाहते हैं। उदाहरण:

public class A extends Something implements ClassTypeInterface {

    public final static String TYPE = "A";

    @Override
    public String getType() {
        return TYPE;
    }
}

उसके बाद आप इसे निम्न तरीके से उपयोग कर सकते हैं:

switch (var.getType()) {
    case A.TYPE: {
        break;
    }
    case B.TYPE: {
        break;
    }
    ...
}

केवल एक चीज जिसे आपको ध्यान रखना चाहिए - क्लासटेपइंटरफेस लागू करने वाले सभी वर्गों में "प्रकार" को अद्वितीय रखें। यह एक बड़ी समस्या नहीं है, क्योंकि किसी भी चौराहे के मामले में आपको "स्विच-केस" स्टेटमेंट के लिए संकलन-समय की त्रुटि मिलती है।


के लिए स्ट्रिंग का उपयोग करने के बजाय TYPE, आप एक एनम का उपयोग कर सकते हैं और विशिष्टता की गारंटी है (जैसा कि इस उत्तर में किया गया है )। हालाँकि, किसी भी दृष्टिकोण के साथ आपको नाम बदलने पर दो स्थानों पर रिफलेक्टर करना होगा।
user905686

@ user905686 का नाम क्या है? वर्तमान उदाहरण में "A" कोड की मात्रा को कम करने के लिए समथिंग क्लास के अंदर परिभाषित किया गया है। लेकिन वास्तविक जीवन में आपको स्पष्ट रूप से इसे बाहर (किसी सामान्य स्थान पर) परिभाषित करना चाहिए और आगे की रिफैक्टिंग के साथ कोई समस्या नहीं है।
सर्गेई क्रिवनकोव

मेरा मतलब है कि ए का नाम बदलने से ए। स्वचालित रीफैक्टरिंग का TYPE = "A"नाम बदलने पर वैरिएबल शामिल नहीं हो सकता है । खासकर यदि यह इसी वर्ग के बाहर है, तो कोई इसे मैन्युअल रूप से करते समय इसे भूल भी सकता है। इंटेलीज वास्तव में स्ट्रिंग या टिप्पणियों में वर्ग के नाम की घटनाओं को भी पाता है, लेकिन यह सिर्फ एक पाठ खोज है (सिंटैक्स ट्री को देखने के बजाय) और इस तरह गलत सकारात्मकता शामिल है।
user905686

@ user905686 यह केवल एक उदाहरण है, विचार की कल्पना करने के लिए। वास्तविक परियोजना में टाइप परिभाषाओं के लिए स्ट्रिंग का उपयोग न करें, कुछ MyTypes वर्ग धारक को पूर्णांक स्थिरांक (या एनम) के साथ घोषित करें और ClassTypeInterface को लागू करने वाली कक्षाओं में उनका उपयोग करें।
सर्गेई क्रिवनकोव

1

यहाँ http://www.vavr.io/ का उपयोग करके जावा 8 में इसे पूरा करने का एक कार्यात्मक तरीका है

import static io.vavr.API.*;
import static io.vavr.Predicates.instanceOf;
public Throwable liftRootCause(final Throwable throwable) {
        return Match(throwable).of(
                Case($(instanceOf(CompletionException.class)), Throwable::getCause),
                Case($(instanceOf(ExecutionException.class)), Throwable::getCause),
                Case($(), th -> th)
        );
    }

1

हालांकि एक स्विच स्टेटमेंट लिखना संभव नहीं है, लेकिन प्रत्येक दिए गए प्रकार के लिए विशिष्ट प्रसंस्करण को शाखा देना संभव है। ऐसा करने का एक तरीका मानक दोहरे प्रेषण तंत्र का उपयोग करना है। एक उदाहरण जहां हम प्रकार पर आधारित "स्विच" करना चाहते हैं जर्सी अपवाद मैपर है जहां हमें त्रुटि प्रतिक्रियाओं के अपवादों की भीड़ को मैप करने की आवश्यकता है। हालांकि इस विशिष्ट मामले के लिए शायद एक बेहतर तरीका है (यानी एक पॉलीमॉर्फिक विधि का उपयोग करना जो प्रत्येक त्रुटि त्रुटि के अपवाद का अनुवाद करता है), दोहरे प्रेषण तंत्र का उपयोग करना अभी भी उपयोगी और व्यावहारिक है।

interface Processable {
    <R> R process(final Processor<R> processor);
}

interface Processor<R> {
    R process(final A a);
    R process(final B b);
    R process(final C c);
    // for each type of Processable
    ...
}

class A implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class B implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class C implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

फिर जहां कभी भी "स्विच" की आवश्यकता होती है, आप इसे निम्नानुसार कर सकते हैं:

public class LogProcessor implements Processor<String> {
    private static final Logger log = Logger.for(LogProcessor.class);

    public void logIt(final Processable base) {
        log.info("Logging for type {}", process(base));
    }

    // Processor methods, these are basically the effective "case" statements
    String process(final A a) {
        return "Stringifying A";
    }

    String process(final B b) {
        return "Stringifying B";
    }

    String process(final C c) {
        return "Stringifying C";
    }
}

यह विज़िटर पैटर्न की तरह दिखता है, जो पहले से ही इस जवाब में चर्चा में था: stackoverflow.com/a/5579385
टाइपरज़र

0

कक्षा के नाम के साथ एक एनम बनाएँ ।

public enum ClassNameEnum {
    A, B, C
}

ऑब्जेक्ट का वर्ग नाम ढूंढें । एनम पर एक स्विच केस लिखें ।

private void switchByClassType(Object obj) {

        ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName());

        switch (className) {
            case A:
                doA();
                break;
            case B:
                doB();
                break;
            case C:
                doC();
                break;
        }
    }
}

उम्मीद है की यह मदद करेगा।


2
इस दृष्टिकोण के विपरीत जहां एनम स्थिरांक और वर्गों के बीच युग्मन स्पष्ट रूप से किया जाता है, आप युग्मन को वर्ग नाम से निहित करते हैं। यह आपके कोड को तब तोड़ देगा जब आप केवल एक एनाम स्थिरांक या वर्ग का नाम बदल देंगे जबकि दूसरा दृष्टिकोण अभी भी काम करेगा।
user905686

0

एक्लिप्स मॉडलिंग फ्रेमवर्क का एक दिलचस्प विचार है जो विरासत पर भी विचार करता है। मूल अवधारणा को स्विच इंटरफ़ेस में परिभाषित किया गया है : स्विचिंग doSwitch विधि द्वारा किया जाता है ।

वास्तव में क्या दिलचस्प है कार्यान्वयन। प्रत्येक प्रकार के ब्याज के लिए, ए

public T caseXXXX(XXXX object);

विधि को लागू किया जाना चाहिए (एक डिफ़ॉल्ट कार्यान्वयन के साथ अशक्त)। DoSwitch कार्यान्वयन अल फोन करने का प्रयास करेंगे caseXXX अपने सभी प्रकार पदानुक्रम के लिए वस्तु पर तरीकों। की पंक्तियों में कुछ:

BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;

वास्तविक रूपरेखा प्रत्येक वर्ग के लिए एक पूर्णांक आईडी का उपयोग करती है, इसलिए तर्क वास्तव में एक शुद्ध स्विच है:

public T doSwitch(Object object) {
    return doSwitch(object.class(), eObject);
}

protected T doSwitch(Class clazz, Object object) {
    return doSwitch(getClassifierID(clazz), object);
}

protected T doSwitch(int classifierID, Object theObject) {
    switch (classifierID) {
    case MyClasses.BASETYPE:
    {
      BaseType baseType = (BaseType)object;
      ...
      return result;
    }
    case MyClasses.TYPE1:
    {
      ...
    }
  ...

आप एक बेहतर विचार प्राप्त करने के लिए ECoreSwitch के पूर्ण कार्यान्वयन को देख सकते हैं।


-1

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

        DEFINE_TYPE:
        {
            if (a instanceof x){
                //do something
                break DEFINE_TYPE;
            }
            if (a instanceof y){
               //do something
                break DEFINE_TYPE;
            }
            if (a instanceof z){
                // do something
                break DEFINE_TYPE;
            }
        }

कैसे यह किसी भी तुलना में बेहतर है if... else ifओ पी द्वारा दिए गए कोड?
टाइपरजर

बस मेरी पिछली टिप्पणी पर विस्तार से बताएं: आप जो प्रस्ताव दे रहे हैं वह अनिवार्य रूप से प्रतिस्थापित करना है if... else if"गोटो" बयानों के साथ, जो जावा जैसी भाषाओं में नियंत्रण प्रवाह को लागू करने का गलत तरीका है।
टाइपरजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.