2016-08-18 5 views
9

मान लीजिए मुझे कुछ कुछ BaseBuilder का विस्तार करने की आवश्यकता है। बेस बिल्डर के पास foo जैसी कुछ विधि है (जो BaseBuilder लौटाती है)। व्युत्पन्न बिल्डर में विधि bar है। विधि विधि foo के बाद विधि लागू की जानी चाहिए। ताकि इसे करने के लिए मैं DerivedBuilder इस तरह में foo विधि ओवरराइड कर सकते हैं:जावा जेनेरिक बिल्डर

@Override 
public DerivedBuilder foo() { 
    super.foo(); 
    return this; 
} 

समस्या BaseBuilderfoo तरह के तरीकों का एक बहुत है और मैं उनमें से हर एक ओवरराइड करने के लिए होता है। मुझे लगता है कि इसलिए मैं जेनरिक का उपयोग करने की कोशिश की करने के लिए नहीं करना चाहती:

public class BaseBuilder<T extends BaseBuilder> { 
    ... 

    public T foo() { 
     ... 
     return (T)this; 
    } 
} 

public class DerivedBuilder<T extends DerivedBuilder> extends BaseBuilder<T> { 
    public T bar() { 
     ... 
     return (T)this; 
    } 
} 

लेकिन समस्या यह है कि मैं अभी भी नहीं लिख सकते हैं

new DerivedBuilder<DerivedBuilder>() 
     .foo() 
     .bar() 

भी T हालांकि यहां DerivedBuilder है। बहुत सारे कार्यों को ओवरराइड न करने के लिए मैं क्या कर सकता हूं?

+1

, आप कॉल कर सकते हैं: 'नई DerivedBuilder ()। foo()। बार() '। यह पहले और फिर 'बार' काम करेगा और 'foo' निष्पादित करेगा। यदि आप 'बेसबिल्डर' के अधिक तरीकों को कॉल करना चाहते हैं और आखिरकार आप 'व्युत्पन्नबिल्डर' विधि को कॉल करना चाहते हैं, तो यह संभव नहीं है, क्योंकि दूसरी बार, विधि 'बेसबिल्डर' का संदर्भ देता है, इसके साथ आप 'व्युत्पन्न बिल्डर' नहीं कह सकते हैं। एस विधि –

+0

@ संदीप.केआई ने इसे निष्पादित करने का प्रयास किया और संकलक शिकायत करता है कि 'बेस' को 'बेसबिल्डर' में परिभाषित नहीं किया गया था, क्योंकि तब मैं '.foo()। Bar() 'करता हूं' केवल एक ही चीज संकलक 'f' निष्पादित करने के बाद' टी 'के बारे में जानता है 'यह है कि यह' टी' 'बेसबिल्डर' – PepeHands

+0

बढ़ाता है [यह] देखें (http://stackoverflow.com/questions/4217013/how-to-force-derived-class-to-call-super-method-like-android -does) और [यह] (http://stackoverflow.com/questions/6853638/require-override-of-method-to-call-super) और [यह] (http://stackoverflow.com/questions/6142460/how-do-i-force-a-polymorphic-call-to-the-super-method) ... – user1803551

उत्तर

5

आपकी समस्या DerivedBuilder की परिभाषा है।

आप एक पूरी तरह से परिभाषित व्युत्पन्न प्रकार, इस तरह की आवश्यकता होगी:

public class BaseBuilder<T extends BaseBuilder<T>> { 
    @SuppressWarnings("unchecked") 
    public T foo() { 
     return (T)this; 
    } 
} 

public class DerivedBuilder extends BaseBuilder<DerivedBuilder> { 
    public DerivedBuilder bar() { 
     return this; 
    } 
} 

चेक ideone.com

+0

क्या 'व्युत्पन्न बिल्डर' को आगे बढ़ाने की संभावना है, उदाहरण के लिए 'सबडिएरबिल्डर'? 'SubDerivedBuilderM <...> DerivedBuilder <...>' –

+1

@MCEmperor हां बढ़ाता है, लेकिन आपको सभी सबसे व्युत्पन्न प्रकारों को अपनी बेस क्लास में पूर्ण प्रकारों को पार करने की आवश्यकता है। [यह कांटा] जांचें (http://ideone.com/ZIAuqs) – BeyelerStudios

0

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

public abstract class BaseBuilder { 

    public void foo(){ 
     System.out.println("foo"); 
    } 

    public abstract void bar(); 

    public void template(){ 
     foo(); 
     bar(); 
    } 
} 

public class DerivedBuilder extends BaseBuilder{ 

    @Override 
    public void bar() { 
     System.out.println("bar");  
    } 

    public static void main(String[] args) { 
     BaseBuilder builder = new DerivedBuilder(); 
     builder.template(); 
    } 
} 


आशा इस मदद करता है।

class DerivedBuilder<T extends DerivedBuilder>; 

और फिर एक प्रकार मिट तर्क new DerivedBuilder<DerivedBuilder<...what?...>>() साथ यह instantiating:

2

return (T) this; कास्टिंग करने के बजाय मैंने यहां Class.cast(this) किया था।

का एहसास करने के लिए:

BaseBuilder.build(ExtendedBuilder.class).foo().bar().foo().bar(); 

hierarch में हर वर्ग वास्तविक अंतिम बच्चे कक्षा में जानने की जरूरत है, इसलिए मैं आधार वर्ग में एक कारखाने विधिbuild बनाने के लिए चुना है।

वास्तविक बच्चे को this का कास्ट बेस क्लास की अंतिम विधि में भी किया जाता है, जो return me(); प्रदान करता है।

class BaseBuilder<B extends BaseBuilder<B>> { 

    protected Class<B> type; 

    public static <T extends BaseBuilder<T>> T build(Class<T> type) { 
     try { 
      T b = type.newInstance(); 
      b.type = type; 
      return b; 
     } catch (InstantiationException | IllegalAccessException e) { 
      throw new IllegalStateException(e); 
     } 
    } 

    protected final B me() { 
     return type.cast(this); 
    } 

    B foo() { 
     System.out.println("foo"); 
     return me(); 
    } 
} 

class ExtendedBuilder extends BaseBuilder<ExtendedBuilder> { 

    ExtendedBuilder bar() { 
     System.out.println("bar"); 
     return me(); 
    } 
} 
+0

और अब आपके पास बिल्डर फैक्टरी है। साथ ही, 'टाइप' फ़ील्ड और' टाइप.कास्ट (यह) 'व्यर्थ है, क्योंकि यह कोई अतिरिक्त संकलन-समय सुरक्षा प्रदान नहीं करता है और पूरी चीज को जटिल बनाता है। – Clashsoft

+0

@XetraSu ने 'स्थिर वर्ग 'का प्रस्ताव दिया जो संभवतः उनके उपयोग को फिट करता है। –

4

BeyelerStudios's answer के अलावा, यदि आप घोंसला करने के लिए आगे चाहते हैं, तो आप सिर्फ इस का उपयोग कर सकते हैं: जेनरिक के इस approch साथ

class Base<T extends Base<?>> { 
    public T alpha() { return (T) this; } 
    public T bravo() { return (T) this; } 
    public T foxtrot() { return (T) this; } 
} 

class Derived<T extends Derived<?>> extends Base<T> { 
    public T charlie() { return (T) this; } 
    public T golf() { return (T) this; } 
} 

class FurtherDerived<T extends FurtherDerived<?>> extends Derived<T> { 
    public T delta() { return (T) this; } 
    public T hotel() { return (T) this; } 
} 

class MuchFurtherDerived<T extends MuchFurtherDerived<?>> extends FurtherDerived<T> { 
    public T echo() { return (T) this; } 
} 

public static void main(String[] args) { 
    new MuchFurtherDerived<MuchFurtherDerived<?>>() 
     .alpha().bravo().charlie().delta().echo().foxtrot().golf().hotel() 
     .bravo().golf().delta().delta().delta().hotel().alpha().echo() 
     .echo().alpha().hotel().foxtrot(); 
} 
संबंधित मुद्दे