2013-05-19 6 views
5

मुझे यकीन है कि यह पहले पूछे जाने चाहिए लेकिन मुझे ऐसा ही उदाहरण नहीं मिल रहा है। मैं अच्छी तरह से polymorphism और विधि overloading समझता हूं, लेकिन यहां एक समाधान के साथ एक साधारण सरल परिदृश्य है जो मुझे बचता है:पॉलिमॉर्फिज्म-पैरामीटर की तरह हैंडलिंग - सरल ओओ?

मान लें कि मेरे पास कई व्युत्पन्न कक्षाओं के साथ बेस क्लास है। मैं इस उदाहरण

base Shape 
derived Circle extends Shape 
derived LineSeg extends Shape 

आदि के लिए आकार का उपयोग करेगा

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

Circle.intersect(LineSeg) 
Circle.intersect(Circle) 
LineSeg.intersect(Circle) 

आदि

अब तक तो अच्छा।

समस्या है, अगर मैं आकार की एक केंद्रीय सूची रखने के लिए, मैं ऐसा करना चाहते हैं:

for some shape s 
Foreach shape in Shapes 
    if (s.intersect(shape)) - do something 

वर्तमान में, मुझे यकीन है कि यह कैसे संभव है, के बाद से विधि ओवरलोडिंग "एक दूसरे को काटना" का चयन करता है नहीं कर रहा हूँ आधार प्रकार आकार से मिलान करने के लिए विधि, और उपयुक्त पैरामीटर प्रकार नहीं। मैं इसे बिना किसी और-श्रृंखला के प्रकार और डाउन-कास्टिंग की जांच कैसे कर सकता हूं?

बीटीडब्ल्यू, मैं जावा का उपयोग कर रहा हूं, लेकिन मुझे यकीन नहीं है कि भाषा पूरी तरह प्रासंगिक है क्योंकि यह मूलभूत डिजाइन प्रश्न प्रतीत होता है। बहुत आसान लगता है, मुझे क्या याद आ रही है?

धन्यवाद!


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

+1

कुछ प्रोग्रामिंग भाषाओं और सीधे तर्क 'क्रम प्रकारों पर अधिक भार समर्थन करते हैं।उदाहरण के लिए, LISP * multimethods * का समर्थन करता है, और मुझे लगता है कि कुछ कार्यात्मक प्रोग्रामिंग भाषाएं इसका समर्थन करती हैं। जावा में, इसे आमतौर पर * डबल प्रेषण * कहा जाता है, और गोफ विज़िटर पैटर्न जाने का तरीका है। –

+1

अपने डिज़ाइन को कम करने के लिए नहीं, लेकिन आपकी विरासत थोड़ा गलत है। रेखा खंड वास्तव में आकार नहीं हैं। वे आकार बनाते हैं। आप आकृति, रेखा खंडों के आधार पर कई में से किसी एक के चौराहे की जांच करेंगे, जो प्रश्न में दो आकार बनाते हैं :) – ChiefTwoPencils

+0

@ सीएलएंग, अच्छी पकड़, लेकिन अगर मैं "दीवार" में लाइनसेग का नाम बदलूं तो क्या होगा? मूल रूप से इसका उपयोग कैसे किया जाता है, लेकिन इसे लाइन को कॉल करने से एसईजी इसे अन्य जटिल आकारों में उपयोग करके अवधारणा को आसान बनाता है – user1922401

उत्तर

3

मेरा पहला विचार विज़िटर पैटर्न था, हर आकार दो विधियों को बहुत अधिक देता है, एक मैं intersect(Shape) और एक doIntersect() विधि प्रति आकार प्रकार पर कॉल करूंगा।

यह इस तरह के बारे में दिखेगा:

interface Shape { 
    public abstract Intersection intersect(Shape other); 

    public abstract Intersection doIntersect(Circle circle); 

    public abstract Intersection doIntersect(LineSeg line); 
} 
class LineSeg implements Shape { 
    @Override 
    public Intersection intersect(Shape other) { 
     return other.doIntersect(this); 
    } 

    Intersection doIntersect(Circle circle) { 
     // Code to intersect with Circle 
    } 

    Intersection doIntersect(LineSeg other) { 
     // Code to intersect with another Lineseg 
    } 
} 

class Circle implements Shape { 
    @Override 
    public Intersection intersect(Shape other) { 
     return other.doIntersect(this); 
    } 

    public Intersection doIntersect(Circle other) { 
     // Code to intersect with another Circle 
    } 

    public Intersection doIntersect(LineSeg segment) { 
     // Code to intersect with LineSeg 
    } 
} 

आप doIntersect तरीकों निजी पैकेज या इन से अलग-अलग नामों हालांकि चुना जा करने के लिए चाहते हो सकता है।

+0

यह शानदार है, धन्यवाद। मेरी समस्या को जल्दी और आसानी से फिक्स्ड। मुझे बेस क्लास में प्रोटोटाइप के रूप में सभी पैरामीटर प्रकार की संभावनाएं जोड़ने की ज़रूरत है, जिससे बच्चों को किसी भी संभावना को संभालने के लिए मजबूर किया जा सकता है। – user1922401

+0

एक अतिरिक्त परिशोधन: आप विशिष्ट तरीकों को नाम देने के बजाय 'intersect() 'सभी विधियों का नाम देने में सक्षम होना चाहिए' doIntersect()'। जहां तक ​​मुझे पता है कि कंपाइलर सबसे विशिष्ट अधिभार को चुनता है जो पहले फिट बैठता है। – confusopoly

+0

धन्यवाद - मैंने पहले ही ऐसा किया है, लेकिन आपके सुझाव को छोड़ने का फैसला किया क्योंकि यह कम भ्रमित हो सकता है। मैंने इसे बेस क्लास में डालने की भी कोशिश की ताकि केवल एक की आवश्यकता हो, लेकिन बेस क्लास विधि में "यह" का उपयोग बेस क्लास प्रकार है, दुर्भाग्यवश (मुझे लगता है क्यों, हालांकि) – user1922401

0

जेनेरिक्स देखें Jdk5

आकृतियाँ < में प्रत्येक आकार के लिए>

0

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

public abstract class Shape { 

    boolean intersect(Shape s); 
} 

public class Circle extends Shape { 

    boolean intersect(Shape s) { 
     ... 
     if(s instanceOf Circle) { 
      .... // Circle intersects cicrcle 
     } else if(s instanceOf Lineseg) { 
      .... // Circle intersects Lneseg 
     } else { 
      throw RuntimeException("Unrecognized shape"); 
     } 

    } 

} 

public class Lineseg extends Shape { 

    boolean intersect(Shape s) { 
     ... 
     if(s instanceOf Circle) { 
      .... // Lineseg intersects circle 
     } else if(s instanceOf Lineseg) { 
      .... // Lineseg intersects lineseg 
     } else { 
      throw RuntimeException("Unrecognized shape"); 
     } 
    } 

} 
+0

क्षमा करें, मैं बिना किसी जवाब के लिए पूछ रहा था कि अगर-प्रकार टाइप-चेन चेन – user1922401

+0

@ user1922401 लेकिन आप व्युत्पन्न कक्षाओं में से प्रत्येक में प्रत्येक व्युत्पन्न कक्षा के लिए एक विधि लिखने के इच्छुक हैं, जो वही है। पॉलिमॉर्फिज्म को संभालने के लिए केवल यही तरीका क्लासिक ओओ तरीका है। – ilomambo

+0

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

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