2011-04-11 14 views
13
public Object foo(int opt){ 
    if (opt == 0) return new String(); 
    else if (opt == 1) return new Integer(1); 
    else if (opt == 2) return new Double(1); 
    else if ... 
    .. and many more 
} 

public void doSomething(String s){..} 
public void doSomething(Integer i){..} 
public void doSomething(Double d){..} 
... and many more doSomething method 

public static void main(String[] args){ 
    ... 
    Object o = foo(x); //x is a value obtained during runtime, e.g. from user input 

    //now I want to call doSomething method 
    // (1) 
    if (o instanceof String) doSomething((String) o); 
    else if (o instanceof Integer) doSomething((Integer) o); 
    else if (o instanceof Double) doSomething((Double) o); 
    ... 
    // (2) 
} 

क्या (1) ... (2) से जुड़े बयान को सरल बनाने का कोई बेहतर तरीका है?
क्या जावा प्रतिबिंब मदद करता है?ऑब्जेक्ट प्रकार का उदाहरण अपने विशिष्ट डेटा प्रकार में "गतिशील रूप से" कैसे डाला जाए?

उत्तर

16

इस कुशलतापूर्वक और साफ तरीके से संभालने का सबसे अच्छा तरीका है foo ऑब्जेक्ट के लिए धारक वर्ग को वापस करना है।

abstract class Holder<T> { 
    private final T object; 

    protected Holder(T object) { this.object = object; } 
    public T get() { return object; } 
    public abstract void doSomething(); 
} 

public Holder foo(int opt) { 
    if (opt == 0) return new Holder<String>("") { 
     public void doSomething() { } 
    }; 
    else if (opt == 1) return new Holder<Integer>(1) { 
     public void doSomething() { } 
    }; 
    else if (opt == 2) return new Holder<Double>(1.0) { 
     public void doSomething() { } 
    }; 
    // many more 
} 

public static void main(String... args) throws IOException { 
    Holder h = foo(x); //x is a value obtained during runtime, e.g. from user input 

    //now I want to call doSomething method 
    h.doSomething(); 
} 
2

असल में आप निष्पादन समय पर ओवरलोड रिज़ॉल्यूशन चाहते हैं - आप इसे बहुत आसानी से करने में सक्षम नहीं होंगे।

में मामले, visitor pattern मदद कर सकते हैं, लेकिन मुझे नहीं लगता कि यह यहां होगा। मुझे लगता है कि आप या तो कोड जो आप यहां हैं, या प्रतिबिंब के साथ अटक गए हैं। मैं कभी भी मेरे कुछ सहयोगियों के रूप में विज़िटर पैटर्न पर उत्सुक नहीं रहा हूं - यह हमेशा थोड़ा गन्दा महसूस करता है - लेकिन यह एक विचार के लायक है।

क्या आप foo को मूल्य लौटने के बजाय सही doSomething अधिभार को कॉल कर सकते हैं? यह कोड का थोड़ा सा है जो जानता है कि क्या बनाया जा रहा है - यदि आप उचित अधिभार के साथ doSomething पर कॉल करने के लिए ऑब्जेक्ट पास कर सकते हैं, तो आप एक ही स्थान पर टाइप-विशिष्ट तर्क के साथ समाप्त हो जाएंगे।

जावा 7 में यह संभव है कि invokedynamic इस तरह की स्थिति में उपयोगी होगा - निश्चित रूप से dynamic टाइप सी # 4 में मदद मिलेगी - लेकिन मैंने निश्चित रूप से कहने के लिए पर्याप्त invokedynamic में नहीं देखा है।

+0

(यह नहीं एक असामान्य सूची संयोग से, प्रतिबिंब अपवाद के मामले में बहुत शोर आम तौर पर है) जैसा कि मुझे पता है कि जावा भाषा में वास्तव में * invocedynamic' बाइटकोड * का उपयोग करने का कोई तरीका नहीं है। मैं इस पर गलत साबित होना चाहता हूं, 'हालांकि। –

+0

@ जोचिम: आह, मैंने सोचा कि जावा 7 में प्रस्तावित भाषा परिवर्तनों में से एक था। मैंने ईमानदार होने के लिए क्या किया है और क्या बाहर है, इसका ट्रैक खो गया है ... –

0

जावा में ऐसा करने का कोई अर्थ नहीं है। जावा को स्थाई रूप से टाइप किया गया है, यदि आप इसे गतिशील रूप से डालना चाहते हैं तो अलग-अलग ऑब्जेक्ट्स पर विभिन्न विधियों को कॉल करने के लिए आपके पास ऐसा करने के लिए एक स्विच स्टेटमेंट होना चाहिए।

उदाहरण - यदि आपके पास स्ट्रिंग या एक इंट है और आप इसे "गतिशील रूप से" डालना चाहते हैं (स्विच के बिना), आप दोनों के लिए क्या ऑपरेशन कर सकते हैं जिन्हें अलग-अलग कोड की आवश्यकता नहीं होती है।

मुझे लगता है कि मैं कह रहा हूं कि अगर आपको डालना है क्योंकि आप दो वस्तुओं (एक अलग विधि) के बारे में कुछ अलग है, तो स्विच के बिना आप वास्तव में उस अलग विधि को कैसे एक्सेस कर सकते हैं?

एक अपवाद आंतरिक चर हो सकता है - जिनके लिए आप जेनेरिक चाहते हैं, लेकिन कक्षाओं के बाहर आंतरिक चर का उपयोग करना एक बुरा विचार है।

ओह, आप शायद वास्तव में क्या चाहते हैं कि सभी वर्ग एक ही इंटरफ़ेस को लागू करें - तब आप नहीं डालेंगे।

कास्टिंग बेहद दुर्लभ होना चाहिए।

3

यहां समस्या चिंता का विषय हो सकती है। जावा एक ऑब्जेक्ट उन्मुख भाषा है, और यह ऑब्जेक्ट उन्मुख तरीके से समस्या को हल करने और हल करने में मदद कर सकता है। इस मामले में, आप पूछ सकते हैं कि क्यों मुख्य ध्यान रखना चाहिए कि किस तरह का ऑब्जेक्ट ओ है। इसके बजाए, आप कक्षाओं का एक समूह रखने पर विचार कर सकते हैं, जिनमें से प्रत्येक जानता है कि अपने तरीके से कुछ कैसे करें।

abstract class Thing { 
    abstract void doSomething(); 
} 

class IntegerThing extends Thing { 
    public void doSomething() { /*whatever*/ }; 
} 

class FloatThing extends Thing { 
    public void doSomething() { /*whatever*/ }; 
} 


//Then later: 

int foo(int type) { 
    if(type == 0) return new IntegerThing(0); 
    if(type == 1) return new FloatThing(7.5); 
    if(type == 3) return new StringThing("Florence"); 
} 

int main(String args[]) { 
    Thing something = foo(x); 
    something.doSomething(); 
} 

आपकी कम महत्वपूर्ण() विधि प्रभावी रूप से एक कारखाना बन जाता है, और उस समय आगे से तुम अब क्या बात की तरह foo द्वारा लौटा दिया गया है के बारे में परवाह करने की जरूरत है।

+0

रिटर्न प्रकार का फू थिंगी होना चाहिए। :) –

2

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

"क्या कुछ" विधियां रखने वाली वस्तु क्या है? इस उदाहरण में, मैं "doOomething" विधि वाले ऑब्जेक्ट का प्रतिनिधित्व करने के लिए वेरिएबल नाम "someObject" का उपयोग करता हूं। आपको कुछ और सनसनीखेज के लिए इसे प्रतिस्थापित करने की आवश्यकता है।

इसके अलावा, केवल एक चेतावनी, यह व्युत्पन्न प्रकारों को नहीं पकड़ेगा, इसलिए यदि विधि परिभाषा दिए गए प्रकार से मेल नहीं खाती है, तो आपको एक विधि अपवाद नहीं मिलेगा।

//now I want to call doSomething method 
// (1) 
Method method = someObject.getClass.getMethod("doSomething",new Class[] {o.getClass()}); 
method.invoke(someObject, new Object[] {o}); 
// (2) 

चेतावनी: आप जब प्रतिबिंब इस तरह का उपयोग कर निम्न अपवादों के साथ सौदा करने की जरूरत है: जहाँ तक

NoSuchMethodException - if a matching method is not found or if the name is "<init>"or "<clinit>". 
NullPointerException - if name is null 
SecurityException - if access to the information is denied. 
IllegalAccessException - if this Method object enforces Java language access control and the underlying method is inaccessible. 
IllegalArgumentException - if the method is an instance method and the specified object argument is not an instance of the class or interface declaring the underlying method (or of a subclass or implementor thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion. 
InvocationTargetException - if the underlying method throws an exception. 
NullPointerException - if the specified object is null and the method is an instance method. 
ExceptionInInitializerError - if the initialization provoked by this method fails. 
संबंधित मुद्दे