2012-06-10 14 views
17

में सबक्लास लौटने पर मैं ऐसी समस्या पर काम कर रहा हूं जहां Foo के कई कार्यान्वयन हैं, कई FooBuilder के साथ। जबकि Foo के शेयर को साझा करने की आवश्यकता वाले कई सामान्य चर, उनके पास विशिष्ट चर भी हैं जिनके लिए कुछ विशिष्ट कार्यक्षमता को लागू करने के लिए उनके संबंधित FooBuilder की आवश्यकता होती है।जावा: सुपरक्लास विधि हस्ताक्षर

public abstract class FooBuilder { 
    ... 

    public FooBuilder setA(int A) { 
    this.A = A; 
    return this; 
    } 

    ... 
} 

और

public class FooImplBuilder extends FooBuilder{ 
    ... 
    public FooImplBuilder setB(int B) { 
    this.B = B; 
    return this; 
    } 
    public FooImplBuilder setC(int C) { 
    this.C = C; 
    return this; 
    } 
    ... 
} 

और इसी तरह, कई अलग अलग FooBuilder कार्यान्वयन के साथ: संक्षिप्तता के लिए, मैं, विधि श्रृंखलन उपयोग करने के लिए की तरह FooBuilder के setters करना चाहते हैं। यह तकनीकी रूप से वह सब कुछ करता है जो मैं चाहता हूं, हालांकि, यह तरीका विधि श्रृंखला के दौरान विधियों के कॉल के क्रम के प्रति संवेदनशील है।

someFoo.setA(a).setB(b)... 

आवश्यकता डेवलपर आदेश के बारे में लगता है कि की विधि श्रृंखला में कॉल: विधि निम्नलिखित है त्रुटियों संकलन अपरिभाषित। इससे बचने के लिए, मैं FooBuilder में सेटर्स को वास्तविक कार्यान्वयन सबक्लास लौटा दूंगा। हालांकि, मुझे यकीन नहीं है कि यह कैसे करें। सबसे अच्छा तरीका क्या है?

+0

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

उत्तर

13

की तरह यह एक अच्छा सवाल है और एक वास्तविक समस्या है।

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

मुद्दे का एक अच्छा चर्चा और Using Inheritance with Fluent Interfaces पर इस ब्लॉग प्रविष्टि है, जो हमेशा सही वर्ग के एक बिल्डर लौटने की समस्या को हल करने के लिए एक getThis() विधि बिल्डर उपवर्गों में ओवरराइड की परिभाषा के साथ जेनरिक को जोड़ती में एक उचित समाधान नहीं है।

+1

मुझे यह समाधान पसंद है। मैंने जो प्रस्तावित किया उससे कहीं अधिक विस्तृत, लेकिन अधिक लचीला और अंततः सुरुचिपूर्ण तरीका भी। – Jochen

+0

बस लिंक किए गए ब्लॉग को सारांशित करने के लिए, और अलग बिल्डर्स को निकालने के लिए: 'सार्वजनिक अमूर्त वर्ग एक्स <बी एक्स > {सार्वजनिक int ए; सार्वजनिक बी सेटए (int foo) {this.a = foo; वापसी getThis();} सार्वजनिक अमूर्त बी getThis();} पब्लिक क्लास वाई एक्स {सार्वजनिक int बी; सार्वजनिक वाई सेटबी (इंट बार) {this.b = bar; वापसी प्राप्त करें यह();} सार्वजनिक वाई getThis() {इसे वापस करें;}} ' –

3

जेनरिक यहां जाने का तरीका हो सकता है।

आप Seta() इस (छद्म कोड) की तरह कुछ

<T> T setA(int a) 

संकलक असली प्रकार यह पता लगाने में सक्षम होना चाहिए, और अगर यह नहीं आप कोड में संकेत दे सकते हैं करता है की घोषणा तो

obj.<RealFoo>setA(42) 
+3

+1: http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html –

+0

पर इस रणनीति का एक अच्छा विवरण है संकलक * प्रकार * को जंजीर में टाइप करने में सक्षम नहीं है विधि आमंत्रण, और प्रत्येक विधि आमंत्रण के लिए प्रकार दोहराव शायद ही एक विकल्प है। – meriton

+0

@ डोनरोबी: आप इसे उत्तर के रूप में क्यों नहीं पोस्ट करते? यह जोचेन की तुलना में बेहतर समाधान होता है और निश्चित रूप से एक अपवित्र के लायक होगा ;-) – meriton

1

this excellent answer मिलने के बाद अब मैं इसे साझा कर रहा हूं।

public class SuperClass<I extends SuperClass> 
{ 
    @SuppressWarnings("unchecked") // If you're annoyed by Lint. 
    public I doStuff(Object withThings) 
    { 
     // Do stuff with things. 
     return (I)this ; // Will always cast to the subclass. Causes the Lint warning. 
    } 
} 

public class ImplementationOne 
extends SuperClass<ImplementationOne> 
{} // doStuff() will return an instance of ImplementationOne 

public class ImplementationTwo 
extends SuperClass<ImplementationTwo> 
{} // doStuff() will return an instance of ImplementationTwo 
संबंधित मुद्दे