2013-02-24 16 views
15

मेरे पास एक अभिभावक वर्ग है, जो चेनर विधियों के संग्रह को परिभाषित करता है (विधियां जो "यह" लौटाती हैं)। मैं कई बाल वर्गों को परिभाषित करना चाहता हूं जिनमें उनके स्वयं के चेनर विधियां हों, लेकिन यह मूल विधियों को "ओवरराइड" भी करती है ताकि अभिभावक वर्ग की बजाय बाल वर्ग का एक उदाहरण लौटाया जा सके।जावा में ओओपी: विधि चेनिंग के साथ वर्ग विरासत

मैं प्रत्येक बच्चे वर्ग में एक ही तरीके को दोहराना नहीं चाहता हूं, यही कारण है कि मेरे पास एक अभिभावक वर्ग है जिसमें सभी बाल वर्ग साझा करने के तरीके शामिल हैं। धन्यवाद।

class Chain { 
    public Chain foo(String s){ 
    ... 
    return this; 
    } 
} 

class ChainChild extends Chain { 
    //I don't want to add a "foo" method to each child class 
    /* 
    public ChildChain foo(String s){ 
    ... 
    return this; 
    } 
    */ 

    public ChainChild bar(boolean b){ 
    ... 
    return this; 
    } 
} 

ChainChild child = new ChainChild(); 
child.foo().bar(); //compile error: foo() returns a "Chain" object which does not define the bar() method. 
+1

संभावित डुप्लिकेट [क्या मेरे पास जावा में एक अमूर्त बिल्डर क्लास है जो असुरक्षित संचालन किए बिना विधि श्रृंखला के साथ हो सकता है?] (Http://stackoverflow.com/questions/5818504/can-i-have-an-abstract-builder- क्लास-इन-जावा-साथ-विधि-चेनिंग-बिना-कर रहे हैं) – artbristol

+0

मैं उत्सुक हूं, आप किस स्थिति में ('child.foo()। bar();') कॉल का उपयोग कर रहे हैं? – vijay

+0

@vijay कुछ सेटिंग्स हैं जो सभी बच्चे वर्गों का उपयोग करते हैं। उदाहरण के लिए, एक विधि एक बूलियन पैरामीटर लेती है जो एक निश्चित सेटिंग को सक्षम/अक्षम करता है। – Michael

उत्तर

13

माता पिता वर्ग कि this रिटर्न अभी भी बच्चे वर्ग की वस्तु के लिए एक संदर्भ वापस आ जाएगी में एक तरीका। आप केवल माता-पिता वर्ग के किसी ऑब्जेक्ट के रूप में इसका इलाज कर पाएंगे (जब तक कि आप इसे नहीं निकालते) लेकिन यह वास्तव में इसके मूल प्रकार का होगा।

आप इस तरह जेनरिक उपयोग करने पर विचार कर सकता है:

// This seems a bit too contrived for my liking. Perhaps someone else will have a better idea. 
public class Parent<T extends Parent<T>> { 
    T foo() { 
     return (T) this; 
    } 
} 

public class Child extends Parent<Child> { 
    public void bar() { 
     Child c = foo(); 
    } 
} 
+0

मुझे एहसास है। लेकिन समस्या यह है कि, हालांकि यह एक ही वस्तु है, मैं बाल वर्ग में विधियों को कॉल नहीं कर सकता क्योंकि ऑब्जेक्ट को मूल वर्ग के रूप में टाइप किया गया है। – Michael

+2

मुझे लगता है कि @ luiggi की तकनीक कम हो सकती है। – OldCurmudgeon

0

तुम बस यह डाली कर सकते हैं।

ChainChild child = new ChainChild(); 
((ChainChild) child.foo()).bar(); 

आप की कोशिश कर सकते:

public ? extends Chain foo() { 
    return this; 
} 

लेकिन मुझे यकीन है कि मदद मिलेगी, भले ही वह संकलित नहीं हूँ।

+0

ईएजी बदसूरत। मैं इसे कास्ट नहीं करना चाहता :) – Michael

+0

'? विस्तारित हो सकता है 'काम कर सकता है, लेकिन मुझे यकीन नहीं है - अनिवार्य रूप से आप जानकारी एकत्र करने की कोशिश कर रहे हैं जो आपके द्वारा छिपी हुई बुनियादी बातों के हिस्से के रूप में छिपा हुआ है। –

+2

दूसरा मामला संकलित नहीं करेगा –

10

मैंने आपकी जरूरतों के आधार पर जेनरिक का उपयोग करके यह नमूना लिखा है।

class Parent { 
    public <T extends Parent> T foo() { 
     return (T)this; 
    } 
} 

class Child extends Parent { 

} 

class AnotherChild extends Parent { 

} 

public class Test { 
    public static void main(String[] args) { 

     Parent p = new Child(); 
     System.out.println(p); 
     Child c = p.foo(); 
     System.out.println(c); 
     //throws ClassCastException here since Child is not AnotherChild 
     AnotherChild ac = p.foo(); 
     System.out.println(ac); 
    } 
} 
+0

हम्म अच्छा है, हालांकि तकनीकी रूप से यह सिर्फ चल रहा है जहां कास्ट होता है। –

+0

@ फिलिप व्हाइटहाउस यही ओपी की तलाश में था। –

+0

यहां समस्या यह है कि टी को कक्षा से नहीं, परिवर्तनीय घोषणा से अनुमानित किया जाता है। – d4n3

1

यहाँ OldCurmudgeon की विधि पर एक सुधार है:

public class Parent<This extends Parent<This>> { 

    @SuppressWarnings("unchecked") 
    private final This THIS = (This)this; 

    public This foo() { 
     //... 
     return THIS; 
    } 

    public This bar() { 
     //... 
     return THIS; 
    }  
} 

public class Child extends Parent<Child> { 

    // you can override super with covariant return type 
    @Override 
    public Child bar() { 
     super.bar(); 

     return this; 
    } 
} 


Child child = 
new Child() 
.foo() 
.bar(); 

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

यह प्रत्येक विधि में अनचेक कास्ट हटा देता है और कोड को स्पष्ट बनाता है।

आप इसके बजाय बच्चे को लौटकर माता-पिता के तरीकों को ओवरराइड कर सकते हैं (कॉन्वेंट रिटर्न प्रकार)।

संबंधित मुद्दे