वंशानुक्रम गलत हो गया


12

मेरे पास कुछ कोड हैं जहां एक अच्छा वंशानुक्रम मॉडल नीचे चला गया है और मैं यह समझने की कोशिश कर रहा हूं कि इसे क्यों और कैसे ठीक किया जाए। मूल रूप से, कल्पना कीजिए कि आपके पास एक चिड़ियाघर पदानुक्रम है:

class Animal  
class Parrot : Animal 
class Elephant : Animal 
class Cow : Animal

आदि।

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

इस तरह के कोड को सुधारने / सुधारने का एक अच्छा तरीका क्या है? यहाँ एक विकल्प केवल प्रकारों की जांच के लिए डायनेमिक_कास्ट का उपयोग करना होगा, लेकिन यह कॉलगर्ल्स को बंद कर देता है और पूरे स्थान पर if-if का एक गुच्छा जोड़ता है। आपके पास यहां अधिक विशिष्ट इंटरफेस हो सकते हैं, लेकिन यदि आपके पास बेस क्लास संदर्भ है, तो इससे बहुत मदद नहीं मिलती है। कोई अन्य सुझाव? उदाहरण?

धन्यवाद!


@ नाम: फिर आपको हाथ से पार्सर्स लिखना होगा। : एस
माटेओ इटालिया

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

1
सभी बाइसन खाओ? [मैंने इसे पहले पोस्ट किया था, लेकिन किसी कारण से इसे हटा दिया गया था, संभवतः हास्यहीन जैकस द्वारा।]
जेम्स मैकनेलिस

क्या CageBuilder को अपनी कक्षा की आवश्यकता है? क्या होगा अगर कोई डिफ़ॉल्ट मेकज विधि है, जिसे प्रत्येक व्यक्तिगत वर्ग द्वारा ओवरराइड किया जा सकता है।
जॉब

1
आप यह उल्लेख करते हैं कि क्या-और-फिर कॉल करने वालों के लिए एक खामी के रूप में अव्यवस्था है, लेकिन जैसे ही कॉलर्स isAfricanBizon () का उपयोग करना शुरू करते हैं वे कोड को अव्यवस्थित रूप से if-then-else के साथ स्वचालित रूप से बंद कर देते हैं। तो यह या तो है तो -AfricanBizon के साथ अव्यवस्था () या अगर-तो-और गतिशील जातियों के साथ अव्यवस्था।
davidk01

जवाबों:


13

ऐसा लगता है कि समस्या को कॉनक्रेक्टवैल () लागू करने के बजाय है, उन्होंने एक फ्लैग कॉल IsAfricanBison () लागू किया, और फिर इस तर्क को स्थानांतरित कर दिया कि दीवार को वर्ग के दायरे से बाहर बदलना चाहिए या नहीं। आपकी कक्षाओं को व्यवहार और आवश्यकताओं को उजागर करना चाहिए, न कि पहचान; इन वर्गों के आपके उपभोक्ताओं को उनके द्वारा बताई गई बातों के आधार पर काम करना चाहिए, न कि उनके आधार पर।


1
-1: केवल यही कहता है कि क्या नहीं करना है। ओपी पहले से ही जानता है कि यह एक बुरा विचार था, इसलिए सवाल।
स्टीवन एवर्स

12

isAfricanBizon () सामान्य नहीं है। मान लीजिए कि आप अपने पशु फार्म को एक हाइपोपोटामस के साथ बढ़ाते हैं, जो बहुत मजबूत है, लेकिन उचित प्रभाव रखने के लिए इफरीकनबिजोन () से सच लौटना सिर्फ मूर्खतापूर्ण होगा।

आप हमेशा इंटरफ़ेस के तरीकों को जोड़ना चाहते हैं जो विशिष्ट प्रश्न का उत्तर देते हैं, इस मामले में यह ताकत की तरह कुछ होगा ()


+1: हर कोई इस विशिष्ट उपयोग के मामले को समायोजित करने के लिए वर्ग के वैचारिक मॉडल को तोड़ रहा है (जो कि विभिन्न प्रकार के जानवरों के गुणों को कूटबद्ध करता है)। एक strengthविधि द्वारा material.canHold(animal)अलग-अलग प्रकार की सामग्री का समर्थन करने के एक स्वच्छ तरीके की अनुमति देकर, इसे समझा जा सकता है ConcreteWall
ऐदन कुलली

मुझे आवश्यकताएँ () संपत्ति दृष्टिकोण दूसरों की अपेक्षा बेहतर लगता है, क्योंकि यह आवश्यक है, क्योंकि यह भविष्य की आवश्यकताओं को सक्षम करने के लिए अधिक लचीला है। शुरुआत के लिए, CageBuilder वर्ग तय करें कि कौन सी सामग्री काफी मजबूत है, और फिर आप आसानी से नई सामग्री के साथ वर्ग का विस्तार कर सकते हैं।
jhocking

3

मुझे लगता है कि आपकी समस्या यह है: आपके पास पुस्तकालय के विभिन्न ग्राहक हैं जो केवल पदानुक्रम के एक सबसेट में रुचि रखते हैं लेकिन आधार वर्ग के लिए एक पॉइंटर / संदर्भ पारित किया जाता है। यह वास्तव में मुद्दा है कि डायनेमिक_कास्ट <> हल करने के लिए है।

डायनेमिक_कास्ट <> का उपयोग कम से कम करना ग्राहकों के डिजाइन की बात है; उन्हें इसका उपयोग यह निर्धारित करने के लिए करना चाहिए कि क्या वस्तु को विशेष उपचार की आवश्यकता है और यदि ऐसा है तो डाउन-कास्टेड रेफरेंस पर सभी ऑपरेशन करें।

यदि आपके पास कार्यक्षमता का "संग्रह" प्रकार है जो कई अलग-अलग उप-पदानुक्रमों पर लागू होता है, तो आप इंटरफ़ेस पैटर्न का उपयोग करना चाह सकते हैं जो जावा और सी # का उपयोग करते हैं; एक वर्चुअल बेस क्लास है जो एक शुद्ध-वर्चुअल क्लास है, और यह निर्धारित करने के लिए कि क्या इसके लिए कोई कार्यान्वयन प्रदान करता है, डायनेमिक_कास्ट <> का उपयोग करें।


1

एक चीज जो आप कर सकते हैं वह उस प्रकार की स्पष्ट जाँच को बदलना है, जैसे isAfricanBison()कि आप वास्तव में जिन गुणों में रुचि रखते हैं, उनकी जाँच के साथ isTooStrong()


1
isTooStrong () किस लिए? आप पशु वर्ग में पिंजरे का विशिष्ट कोड जोड़ रहे हैं।
स्टीवन एवर्स

1

जानवरों को कंक्रीट की दीवारों की परवाह नहीं करनी चाहिए। शायद आप इसे सरल मूल्यों के साथ व्यक्त कर सकते हैं।

class Animal {
public:
  virtual ~Animal() {}
  virtual size_t height() const = 0;
  virtual size_t weight() const = 0;
  virtual bool isStrong() const = 0;
};

Cage *CreateCageFromSQL(Animal &a);
Cage *CreateCageFromOrangePeelsAndSticks(Animal &a);

मुझे संदेह है कि हालांकि व्यवहार्य नहीं है। हालांकि, खिलौने के उदाहरणों के साथ यही समस्या है।

मैं कभी भी किसी भी दर पर RequConcreteWalls () या डायनामिक पॉइंटर कास्ट की लाइनों और लाइनों को नहीं देखना चाहूंगा।

यह आमतौर पर एक सस्ता उपाय है। इसे बनाए रखना और अवधारणा करना आसान है। और वास्तव में, समस्या यह बताती है कि इसका जानवर वैसे भी बंधा हुआ है।

class Animal {
public:
  virtual ~Animal() {}
  virtual CageBuilder *getCageBuilder() = 0;
};

यह आपको साझा कोड का उपयोग करने से रोकता नहीं है, बस पशु को थोड़ा प्रदूषित करता है।

लेकिन पिंजरा कैसे बनाया जाता है यह किसी अन्य प्रणाली की नीति हो सकती है, और शायद आपके पास प्रति जानवर एक से अधिक प्रकार के पिंजरे बिल्डर हैं। वहाँ कई अजीब और जटिल संयोजन आप के साथ आ सकते हैं।

मैंने अच्छे छोरों के लिए घटक आधारित डिज़ाइन का उपयोग किया है, इसके साथ मुख्य समस्या यह है कि जब पशु का स्वामित्व साझा किया जाता है तो यह परेशानी हो सकती है। कैसे विनाशकारी में फेंकने से बचने के लिए दर्द बिंदु है।

डबल डिस्पैच एक और विकल्प है, हालांकि मैं हमेशा इसमें कूदने के लिए मितभाषी रहा हूं।

परे कि समस्या का अनुमान लगाना कठिन है।


0

निश्चित रूप से सभी जानवरों के पास निहित संपत्ति है attemptEscape()। जबकि कुछ विधि falseसभी परिदृश्यों में परिणाम दे सकती है, जबकि अन्य के पास अपने अन्य आंतरिक विशेषताओं जैसे sizeऔर के उत्तराधिकार के आधार पर एक मौका हो सकता है weight। तो निश्चित रूप से कुछ बिंदु पर attemptEscape()तुच्छ हो जाता है क्योंकि यह निश्चित रूप से वापस आ जाएगा true

मुझे डर है कि मैं आपके प्रश्न को पूरी तरह से समझ नहीं पा रहा हूं ... सभी जानवरों के पास संबंधित क्रियाएं और विशेषताएं हैं। जानवर के लिए विशिष्ट वन को पेश किया जाना चाहिए जहां यह फिटिंग है। सीधे तोते को बाइसन से संबंधित करने की कोशिश करना एक अच्छा वंशानुक्रम सेटअप नहीं है और वास्तव में एक उचित डिजाइन में एक मुद्दा नहीं होना चाहिए।


-1

एक अन्य विकल्प एक कारखाने का उपयोग करना होगा जो प्रत्येक जानवर के लिए उपयुक्त पिंजरे बनाता है। मुझे लगता है कि यह बेहतर हो सकता है जब उनमें से प्रत्येक के लिए स्थिति अलग हो। लेकिन अगर यह सिर्फ एक शर्त है तो उपर्युक्त RequiresConcreteWall()विधि इसे करेगी।



-2

ऐसा कुछ क्यों नहीं किया

class Animals { /***/ } class HeavyAnimals{} : Animals //The basic class for animals like the African Bison

क्लास हैवीएनिमल्स के साथ आप हैवीएनिमल्स क्लास का विस्तार करके अफ्रीकी बाइसन क्लास बना सकते हैं।

तो अब आप मूल वर्ग (एनिमल्स) का उपयोग कर सकते हैं, जिसका उपयोग अन्य बेस क्लास जैसे हैवीअनिमल वर्ग के साथ किया जा सकता है, जिसका उपयोग अफ्रीकी बाइसन क्लास और अन्य हेवी एनिमल्स बनाने के लिए किया जा सकता है। इसलिए अफ्रीकी बाइसन के साथ अब आपके पास एनीमल क्लास के तरीके और प्रॉपर्टी (यह सभी जानवरों के लिए आधार है) और हेवीअनिमल्स क्लास तक पहुंच है (यह हैवी एनिमल्स के लिए बेस है)


2
यह मिक्स-इन या विशेषता के रूप में काम कर सकता है, लेकिन निश्चित रूप से उपवर्ग के रूप में नहीं। अगली बार जब एक और संपत्ति की आवश्यकता होती है, तो यह कई विरासत के लिए भीख माँग रहा होता है।
साधारण जूल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.