घोड़ों के झुंड को देखते हुए, मैं सभी गेंडा की औसत सींग लंबाई कैसे पता करूँ?


30

उपरोक्त प्रश्न एक सामान्य समस्या का एक सार उदाहरण है जिसका मैं विरासत कोड में सामना करता हूं, या अधिक सटीक रूप से, इस समस्या को हल करने में पिछले प्रयासों के परिणामस्वरूप समस्याएं।

मैं कम से कम एक .NET फ्रेमवर्क विधि के बारे में सोच सकता हूं जो इस समस्या को हल करने के लिए है, Enumerable.OfType<T>विधि की तरह । लेकिन तथ्य यह है कि आप अंततः एक वस्तु के प्रकार को रनटाइम पर पूछताछ करते हैं, मेरे साथ सही नहीं बैठता है।

प्रत्येक घोड़े से परे "क्या आप एक गेंडा हैं?" निम्नलिखित दृष्टिकोण भी दिमाग में आते हैं:

  • जब एक गैर-गेंडा के सींग की लंबाई प्राप्त करने का प्रयास किया जाता है, तो एक अपवाद को फेंक दें (प्रत्येक महल के लिए कार्यक्षमता उपयुक्त नहीं है)
  • एक गैर-गेंडा के सींग की लंबाई के लिए एक डिफ़ॉल्ट या जादू का मूल्य लौटाएं (घोड़ों के एक समूह पर सींग के आँकड़ों की भरपाई करने के लिए डिफ़ॉल्ट चेक की आवश्यकता होती है जो सभी गैर-यूनिकॉर्न हो सकते हैं)
  • विरासत के साथ दूर करो और घोड़े पर एक अलग वस्तु बनाएं जो आपको बताता है कि घोड़ा एक गेंडा है या नहीं (जो संभावित रूप से एक ही समस्या को एक परत के नीचे धकेल रहा है)

मुझे लग रहा है कि यह "गैर-उत्तर" के साथ सबसे अच्छा जवाब देने वाला है। लेकिन आप इस समस्या को कैसे देखते हैं और अगर यह निर्भर करता है, तो आपके फैसले के आसपास का संदर्भ क्या है?

मैं किसी भी अंतर्दृष्टि में दिलचस्पी लेता हूं कि क्या यह समस्या अभी भी कार्यात्मक कोड में मौजूद है (या शायद यह केवल कार्यात्मक भाषाओं में मौजूद है जो कि परिवर्तनशीलता का समर्थन करते हैं?)

यह निम्नलिखित प्रश्न के संभावित डुप्लिकेट के रूप में चिह्नित किया गया था: डाउनकास्टिंग से कैसे बचें?

उस प्रश्न का उत्तर मानता है कि एक के कब्जे में HornMeasurerहै जिसके द्वारा सभी सींग माप किए जाने चाहिए। लेकिन यह एक कोडबेस पर काफी थोपा गया है जो समतावादी सिद्धांत के तहत बनाया गया था कि हर किसी को घोड़े के सींग को मापने के लिए स्वतंत्र होना चाहिए।

अनुपस्थित HornMeasurer, स्वीकृत उत्तर का दृष्टिकोण ऊपर सूचीबद्ध अपवाद आधारित दृष्टिकोण को दर्शाता है।

टिप्पणियों में कुछ भ्रम भी है कि क्या घोड़े और गेंडा दोनों समान हैं, या यदि एक गेंडा घोड़े की एक जादुई उप-प्रजाति है। दोनों संभावनाओं पर विचार किया जाना चाहिए - शायद एक दूसरे के लिए बेहतर है?


22
घोड़ों के सींग नहीं होते हैं, इसलिए औसत अपरिभाषित होता है (0/0)।
स्कॉट व्हिटलॉक

3
@Marboilerplate 10 से अनंत तक कहीं भी।
नानी

4
@StephenP: इस मामले के लिए गणितीय रूप से काम नहीं करेगा; उन सभी 0s औसत तिरछा होगा।
मेसन व्हीलर

3
यदि आपके प्रश्न का उत्तर गैर-उत्तर के साथ दिया गया है, तो यह प्रश्नोत्तर साइट पर नहीं है; Reddit, quora, या अन्य चर्चा आधारित साइटें गैर-उत्तर प्रकार के सामान के लिए बनाई गई हैं ... उन्होंने कहा, मुझे लगता है कि यह स्पष्ट रूप से जवाब देने योग्य हो सकता है यदि आप उस कोड की तलाश कर रहे हैं जो @MasonWheeler ने दिया है, अगर मुझे नहीं लगता कि मुझे कोई पता नहीं है आप पूछने की कोशिश कर रहे हैं ..
जिमी हॉफ

3
@JimmyHoffa "आप इसे गलत कर रहे हैं" एक स्वीकार्य "गैर-उत्तर," और "बेहतर से बेहतर" होता है, यहाँ एक तरीका यह है कि आप इसे कर सकते हैं - कोई विस्तारित चर्चा की आवश्यकता नहीं है।
moarboilerplate

जवाबों:


11

यह मानते हुए कि आप Unicornएक विशेष प्रकार का उपचार करना चाहते Horseहैं, मूल रूप से दो तरीके हैं जिनसे आप इसे मॉडल कर सकते हैं। अधिक पारंपरिक तरीका उपवर्ग संबंध है। आप अपने कोड को हमेशा केवल संदर्भों में अलग रखने के लिए अपने कोड को दर्शाते हुए टाइप और डाउनकास्टिंग से बच सकते हैं, जहां यह मायने रखता है, और केवल उन संदर्भों में उन्हें संयोजित करें जहां आप Unicornलक्षणों के बारे में कभी परवाह नहीं करते हैं। दूसरे शब्दों में, आप इसे व्यवस्थित करते हैं इसलिए आप कभी भी उस स्थिति में नहीं आते हैं जहां आपको पहली जगह में घोड़ों के झुंड से इकसिंगों को निकालने की आवश्यकता होती है। यह पहली बार में मुश्किल लगता है, लेकिन 99.99% मामलों में संभव है, और आमतौर पर वास्तव में आपके कोड को बहुत क्लीनर बनाता है।

जिस तरह से आप एक गेंडा मॉडल कर सकते हैं वह सभी घोड़ों को एक वैकल्पिक सींग की लंबाई देकर है। तब आप यह देख सकते हैं कि यदि यह एक सींग की लंबाई है, तो यह जाँच कर कि यह एक गेंडा है या नहीं (स्केल द्वारा)

case class Horse(val hornLength: Option[Double])

val horse = Horse(None)
val unicorn = Horse(Some(12.0))
val anotherUnicorn = Horse(Some(6.0))

val herd = List(horse, unicorn, anotherUnicorn)
val hornLengths = herd flatMap {_.hornLength}
val averageLength = hornLengths.sum / hornLengths.size

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


7
बेशक, यह मानता है कि एक साधारण घोड़े और एक गेंडा के बीच एकमात्र अंतर सींग है। यदि यह मामला नहीं है, तो चीजें बहुत अधिक जटिल हो जाती हैं।
मेसन व्हीलर

@MasonWheeler प्रस्तुत दूसरी विधि में ही।
मोहरबेलरपेट

1
गैर-इकसिंगों और इकसिंगों के बारे में टिप्पणियों के साथ हाजिर करें जब तक कि आप एक संदर्भ में नहीं होते हैं, जब तक कि आप एक ऐसे संदर्भ में नहीं होते हैं जब तक कि एक विरासत परिदृश्य में एक साथ पेन नहीं होना चाहिए। ज़रूर .OfType () समस्या को हल कर सकता है और काम कर सकने वाली चीज़ें प्राप्त कर सकता है, लेकिन यह एक ऐसी समस्या को हल कर रहा है जो पहली जगह में भी नहीं होनी चाहिए। दूसरे दृष्टिकोण के लिए, यह काम करता है क्योंकि विकल्प कुछ बेहतर करने के लिए अशक्त पर भरोसा करने से बेहतर हैं। मुझे लगता है कि ओओ में दूसरे दृष्टिकोण को एक समझौता के साथ प्राप्त किया जा सकता है यदि आप एक स्वसंपूर्ण संपत्ति में गेंडा लक्षण का एनकाउंटर करते हैं और बेहद सतर्क हैं।
मोरबोइलरप्लेट

1
समझौता करें यदि आप एक स्वसंपूर्ण संपत्ति में इकसिंगों के गुणों का एनकाउंटर करते हैं और बेहद सतर्क हैं - तो अपने लिए जीवन कठिन क्यों बनाएं। सीधे टाइपोफ़ का उपयोग करें और भविष्य के मुद्दों का एक टन बचाएं।
gbjbaanb

@ GBjbaanb मैं उस दृष्टिकोण पर विचार करूंगा जो वास्तव में उन परिदृश्यों के लिए उपयुक्त है जहां एक एनीमिक के Horseपास IsUnicornसंपत्ति थी और UnicornStuffउस पर सींग की लंबाई के साथ कुछ प्रकार की संपत्ति थी (जब आपके प्रश्न में उल्लिखित सवार / चमक के लिए स्केलिंग)।
मोरबोइलरप्लेट

38

आपने सभी विकल्पों को कवर कर लिया है। यदि आपके पास ऐसा व्यवहार है जो एक विशिष्ट उप-प्रकार पर निर्भर है, और यह अन्य प्रकारों के साथ मिश्रित है, तो आपके कोड को उस उप-प्रकार के बारे में पता होना चाहिए; यह सरल तार्किक तर्क है।

व्यक्तिगत रूप से, मैं अभी जाऊँगा horses.OfType<Unicorn>().Average(u => u.HornLength)। यह कोड के इरादे को बहुत स्पष्ट रूप से व्यक्त करता है, जो अक्सर किसी के बाद में इसे बनाए रखने के लिए किसी के जाने के बाद से सबसे महत्वपूर्ण बात है।


कृपया मुझे माफ़ करें अगर मेरा लंबोदर सिंटैक्स सही नहीं है; मैं C # कोडर का बहुत अधिक नहीं हूं और मैं सीधे इस तरह के आर्कषक विवरण नहीं रख सकता। यह स्पष्ट होना चाहिए कि मेरा क्या मतलब है, हालांकि।
मेसन व्हीलर

1
कोई चिंता नहीं है, समस्या बहुत हल हो गई है एक बार सूची में केवल Unicornवैसे भी शामिल है (रिकॉर्ड के लिए आप छोड़ सकते हैं return)।
मूरबॉइलरप्लेट

4
यह वह उत्तर है जिसके लिए मैं जाऊंगा यदि मैं समस्या को शीघ्र हल करना चाहता था। लेकिन जवाब नहीं अगर मैं कोड को अधिक प्रशंसनीय बनाना चाहता था।
एंडी

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

1
@DavidGrinberg क्या होगा अगर यह साफ, पठनीय विधि लिखने का मतलब है कि आपको पहले एक विरासत संरचना को लागू करना होगा जो पहले मौजूद था?
मोरबोइलरप्लेट

9

.NET में कुछ भी गलत नहीं है:

var unicorn = animal as Unicorn;
if(unicorn != null)
{
    sum += unicorn.HornLength;
    count++;
}

Linq समकक्ष का उपयोग करना भी ठीक है:

var averageUnicornHornLength = animals
    .OfType<Unicorn>()
    .Select(x => x.HornLength)
    .Average();

शीर्षक में पूछे गए प्रश्न के आधार पर, यह वह कोड है जिसे मैं खोजने की उम्मीद करूंगा। यदि प्रश्न कुछ ऐसा पूछा जाता है जैसे "सींग वाले जानवरों का औसत क्या है" जो कि अलग होगा:

var averageHornedAnimalHornLength = animals
    .OfType<IHornedAnimal>()
    .Select(x => x.HornLength)
    .Average();

नोट जब, LINQ का उपयोग कर कि Average(और Minऔर Max) यदि गणनीय खाली है एक अपवाद फेंक और प्रकार टी नल नहीं है जाएगा। ऐसा इसलिए है क्योंकि औसत वास्तव में अपरिभाषित है (0/0)। तो वास्तव में आपको कुछ इस तरह की आवश्यकता है:

var hornedAnimals = animals
    .OfType<IHornedAnimal>()
    .ToList();
if(hornedAnimals.Count > 0)
{
    var averageHornLengthOfHornedAnimals = hornedAnimals
        .Average(x => x.HornLength);
}
else
{
    // deal with it in your own way...
}

संपादित करें

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

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

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

अंत में, वस्तुओं का संग्रह लेना और उसे फ़िल्टर करना वास्तव में केवल कार्यात्मक प्रोग्रामिंग है, न कि ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग। शुक्र है कि C # जैसी भाषाएं अब दोनों प्रतिमानों को संभालने में सहज हैं।


7
आप पहले से ही जानते हैं कि animal Unicorn ; बस का उपयोग करने के बजाय कास्ट as, या संभवतः भी बेहतर उपयोग as और फिर अशक्त के लिए जाँच करें।
फिलिप केंडल

3

लेकिन तथ्य यह है कि आप अंततः एक वस्तु के प्रकार को रनटाइम पर पूछताछ करते हैं, मेरे साथ सही नहीं बैठता है।

इस कथन के साथ परेशानी यह है कि, चाहे आप किसी भी तंत्र का उपयोग करें, आप हमेशा वस्तु से पूछताछ करेंगे कि वह किस प्रकार का है। यह RTTI हो सकता है या यह एक संघ या एक सादा डेटा संरचना हो सकती है जहाँ आप पूछते हैं if horn > 0। सटीक बारीकियों में थोड़ा बदलाव होता है, लेकिन इरादे एक ही होते हैं - आप वस्तु के बारे में खुद से किसी तरह से यह देखने के लिए पूछते हैं कि क्या आपको आगे पूछताछ करनी चाहिए।

यह देखते हुए, ऐसा करने के लिए आपकी भाषा के समर्थन का उपयोग करना समझ में आता है। .NET में आप typeofउदाहरण के लिए उपयोग करेंगे।

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

यदि रनटाइम के दौरान किसी ऑब्जेक्ट के प्रकार की जाँच करना ठीक नहीं है, तो आपका विकल्प शुरू से ही अलग-अलग ऑब्जेक्ट्स को विभाजित करना है - यूनिकॉर्न / घोड़ों के एक झुंड को संग्रहीत करने के बजाय, आप 2 संग्रह रखते हैं - एक घोड़ों के लिए, एक गेंडा के लिए । यह बहुत अच्छी तरह से काम कर सकता है, भले ही आप उन्हें एक विशेष कंटेनर में स्टोर करें (उदाहरण के लिए एक मल्टीपैप जहां कुंजी ऑब्जेक्ट प्रकार है ... लेकिन फिर भी हम उन्हें 2 समूहों में स्टोर करते हैं, हम ऑब्जेक्ट प्रकार से पूछताछ करने के लिए सही हैं !)

निश्चित रूप से एक अपवाद आधारित दृष्टिकोण गलत है। सामान्य प्रोग्राम प्रवाह के रूप में अपवादों का उपयोग करना एक कोड गंध है (यदि आपके पास यूनिकॉर्न्स का एक झुंड है और एक सीकलेस वाला गधा अपने सिर से टकराया है, तो मैं कहूंगा कि अपवाद आधारित दृष्टिकोण ठीक है, लेकिन अगर आपके पास इकसिंगों का झुंड है और घोड़ों को तब इकसिंगा-नेस के लिए प्रत्येक की जाँच अप्रत्याशित नहीं है। अपवाद असाधारण परिस्थितियों के लिए हैं, एक जटिल ifबयान नहीं)। किसी भी स्थिति में, इस समस्या के अपवाद का उपयोग करते हुए बस रनटाइम पर ऑब्जेक्ट प्रकार से पूछताछ की जाती है, केवल यहां आप गैर-गेंडा ऑब्जेक्ट्स की जांच के लिए भाषा सुविधा का दुरुपयोग कर रहे हैं। आप एक कोड के रूप में अच्छी तरह से हो सकता हैif horn > 0 और कम से कम अपने संग्रह को जल्दी से, स्पष्ट रूप से, कोड की कम पंक्तियों का उपयोग करके और अन्य अपवादों को फेंकने से उठने वाली किसी भी समस्या से बचने के लिए (जैसे एक खाली संग्रह, या उस गधे के सीशेल को मापने की कोशिश करना)


एक विरासत के संदर्भ में, if horn > 0इस समस्या को पहली बार में हल करने का तरीका बहुत सुंदर है। तब समस्याएं जो आमतौर पर फसल होती हैं जब आप सवार और चमक की जांच करना चाहते हैं, और horn > 0सभी जगह असंबंधित कोड में दफन किया जाता है (जब सींग 0 होता है, तो चेक की कमी के कारण भी कोड रहस्य कीड़े से ग्रस्त होता है)। इसके अलावा, इस तथ्य के बाद घोड़े को उपवर्गित करना आमतौर पर सबसे महंगा प्रस्ताव है, इसलिए मैं आमतौर पर इसे करने के लिए इच्छुक नहीं हूं, अगर वे अभी भी रिफ्लेक्टर के अंत में एक साथ जमा किए जाते हैं। तो यह निश्चित रूप से "बस कैसे बदसूरत विकल्प हैं" हो जाता है
moarboilerplate

@moarilerplate आप इसे स्वयं कहते हैं, सस्ते और आसान समाधान के साथ जाएं और यह एक गड़बड़ में बदल जाएगा। यही कारण है कि ओओ भाषाओं का आविष्कार किया गया था, इस तरह की समस्या के समाधान के रूप में। सबक्लासिंग घोड़ा पहली बार में महंगा लग सकता है, लेकिन जल्द ही अपने लिए भुगतान करता है। समय के साथ सरल, लेकिन मैला हो रहा है, समाधान अधिक से अधिक खर्च होता है।
gbjbaanb

3

चूँकि प्रश्न में एक functional-programmingटैग है, इसलिए हम दो प्रकारों का उपयोग कर सकते हैं ताकि घोड़ों के दो स्वादों को प्रतिबिंबित कर सकें और उन दोनों के बीच मिलान करने के लिए पैटर्न। उदाहरण के लिए, F # में:

type Equine =
| Horse
| Unicorn of hornLength: float

module equines =

  let averageHornLength (equines : Equine list) =
    equines 
    |> List.choose (fun x -> 
      match x with
      | Unicorn u -> Some(u)
      | _ -> None)
    |> List.average

let herd = [ Horse ; Horse ; Unicorn(35.0) ; Horse ; Unicorn(50.0) ]

printfn "Average horn length in herd : %f" (equines.averageHornLength herd) // prints 42.5

ओओपी से अधिक, एफपी में डेटा / फ़ंक्शंस जुदाई का लाभ होता है, जो शायद आपको सुपरटेप की वस्तुओं की सूची से विशिष्ट उपप्रकारों में परिवर्तित करते समय अमूर्तता के स्तर का उल्लंघन करने वाले (अन्यायपूर्ण?) "दोषी विवेक" से बचाता है।

अन्य उत्तरों में प्रस्तावित OO समाधानों के विपरीत, पैटर्न मिलान भी एक आसान विस्तार प्रदान करता है, Equineएक दिन में शो की एक और हॉर्नेड प्रजाति होनी चाहिए ।


2

अंत में एक ही उत्तर के लघु रूप में पुस्तक या वेब लेख पढ़ने की आवश्यकता होती है।

आगंतुक पैटर्न

समस्या में घोड़ों और गेंडा का मिश्रण है। (लिस्कोव प्रतिस्थापन सिद्धांत का उल्लंघन करना विरासत कोडबेस में एक आम समस्या है।)

घोड़े और सभी उपवर्गों के लिए एक विधि जोड़ें

Horse.visit(EquineVisitor v)

इक्वाइन विज़िटर इंटरफ़ेस जावा / c # में कुछ इस तरह दिखता है

interface EquineVisitor {
  void visitHorse(Horse z);
  void visitUnicorn(Unicorn z);
}

Unicorn.visit(EquineVisitor v){
   v.visitUnicorn(this);
}

Horse.visit(EquineVisitor v){
   v.visitHorse(this);
}

सींगों को मापने के लिए अब हम लिखते हैं ...।

class HornMeasurer implements EquineVistor {
    void visitHorse(Horse h){} // ignore horses
    void visitUnicorn(Unicorn u){
         double len = u.getHornLength();
         totalLength+=len;
         unicornCount++;
    }

    double getAverageLength(){
          return totalLength/unicornCount;
    }

    double totalLength=0;
    int unicornCount=0;
}

विज़िटर पैटर्न की आलोचना रिफैक्टिंग और विकास को कठिन बनाने के लिए की जाती है।

संक्षिप्त उत्तर: डबल प्रेषण प्राप्त करने के लिए डिज़ाइन पैटर्न विज़िटर का उपयोग करें।

https://en.wikipedia.org/wiki/Visitor_pattern भी देखें

आगंतुकों की चर्चा के लिए http://c2.com/cgi/wiki?VisitorPattern भी देखें ।

गामा एट अल द्वारा डिजाइन पैटर्न भी देखें।


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

0

यह मानते हुए कि आपकी वास्तुकला में इकाइयां घोड़े की एक उप-प्रजाति हैं और आप ऐसे स्थानों का सामना करते हैं जहाँ आपको कुछ संग्रह प्राप्त Horseहो सकते हैं Unicorn, मैं व्यक्तिगत रूप से पहली विधि के साथ जाऊँगा ( .OfType<Unicorn>()...) क्योंकि यह आपके इरादे को व्यक्त करने का सबसे सरल तरीका है । जो कोई भी बाद में (3 महीनों में अपने आप को) साथ लेकर आता है, यह तुरंत स्पष्ट हो जाता है कि आप उस कोड को पूरा करने की कोशिश कर रहे हैं: घोड़ों में से इकसिंगों को बाहर निकालें।

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

foreach (var horse in horses)
{
    try
    {
        var length = horse.MeasureHorn();
        //...
    }
    catch (NoHornException e)
    {
        continue;
    }
}

तो अब अपवाद यह संकेतक बन गया है कि कुछ एक गेंडा नहीं है। और अब यह वास्तव में कोई असाधारण स्थिति नहीं है, बल्कि सामान्य कार्यक्रम प्रवाह का हिस्सा है। और ifकेवल एक प्रकार का चेक करने की तुलना में भी अधिक गंदा लगता है एक अपवाद का उपयोग करना ।

कहते हैं कि आप घोड़ों पर सींग की जाँच के लिए जादू मूल्य मार्ग पर चलते हैं। तो अब आपकी कक्षाएं कुछ इस तरह दिखती हैं:

class Horse
{
    public double MeasureHorn() { return -1; }
    //...
}

class Unicorn : Horse
{
    public override double MeasureHorn { return _hornLength; }
    //...
}

अब आपकी Horseकक्षा को कक्षा के बारे में जानना होगा Unicornऔर उसके पास उन चीजों से निपटने के लिए अतिरिक्त तरीके होंगे जिनकी उसे परवाह नहीं है। अब कल्पना आप भी है Pegasusऔर Zebraसे है कि इनहेरिट है Horse। अब Horseएक की जरूरत है Flyऔर साथ ही विधि MeasureWings, CountStripesआदि और फिर Unicornवर्ग इन तरीकों भी हो जाता है। अब आपकी कक्षाओं को सभी को एक-दूसरे के बारे में जानना है और आपने कक्षाओं को कई तरीकों से प्रदूषित कर दिया है जो कि टाइप सिस्टम से पूछने से बचने के लिए नहीं होना चाहिए "क्या यह एक गेंडा है?"

तो क्या कुछ जोड़ने के बारे में Horseकहने के लिए अगर कुछ एक है Unicornऔर सभी सींग मापने को संभालता है? ठीक है, अब आपको यह जानने के लिए इस वस्तु के अस्तित्व की जांच करनी है कि क्या कुछ एक गेंडा है (जो सिर्फ एक चेक को दूसरे के लिए प्रतिस्थापित कर रहा है)। यह पानी को थोड़ा-थोड़ा पिघलाता है, अब आपके पास एक हो सकता हैList<Horse> unicornsयह वास्तव में सभी गेंडा रखता है, लेकिन प्रकार प्रणाली और डिबगर आसानी से आपको यह नहीं बता सकता है। "लेकिन मुझे पता है कि यह सब कुछ है" आप कहते हैं, "नाम भी ऐसा कहता है।" अच्छा, अगर किसी का नाम खराब किया गया तो क्या होगा? या कहें, आपने इस धारणा के साथ कुछ लिखा है कि यह वास्तव में सभी इकसिंगें होंगे, लेकिन तब आवश्यकताएं बदल गईं और अब इसमें पेगासी भी मिलाया जा सकता है? (क्योंकि इस तरह का कुछ भी कभी नहीं होता है, विशेषकर विरासत सॉफ्टवेयर / कटाक्ष में।) अब टाइप सिस्टम ख़ुशी-ख़ुशी आपके पेगासी को आपके यूनिकॉर्न में डाल देगा। यदि आपके चर को List<Unicorn>कंपाइलर (या रनटाइम वातावरण) के रूप में घोषित किया गया था, अगर आप पेगासी या घोड़ों में मिश्रण करने की कोशिश करते हैं तो एक फिट होगा।

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

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


मौन अपवाद निश्चित रूप से बुरा है - मेरा प्रस्ताव एक चेक था जो होगा if(horse.IsUnicorn) horse.MeasureHorn();और अपवादों को नहीं पकड़ा जाएगा - या तो उन्हें ट्रिगर किया जाएगा जब !horse.IsUnicornआप एक गेंडा-मापने के संदर्भ में, या MeasureHornएक गैर-इकसिंगें के अंदर होंगे । इस तरह से जब अपवाद फेंका जाता है तो आप मास्क की त्रुटियां नहीं करते हैं, यह पूरी तरह से उड़ जाता है और यह संकेत है कि कुछ को ठीक करने की आवश्यकता है। जाहिर है कि यह केवल कुछ परिदृश्यों के लिए उपयुक्त है, लेकिन यह एक कार्यान्वयन है जो निष्पादन पथ को निर्धारित करने के लिए अपवाद फेंकने का उपयोग नहीं करता है।
moarboilerplate

0

ठीक है, ऐसा लगता है कि आपके शब्दार्थ डोमेन का IS-A संबंध है, लेकिन आप इसे मॉडल करने के लिए उपप्रकार / वंशानुक्रम का उपयोग करने से थोड़ा सावधान हैं - विशेष रूप से रनटाइम प्रकार प्रतिबिंब के कारण। हालांकि मुझे लगता है कि आप गलत चीज़ से डर गए हैं- सबटाइपिंग वास्तव में खतरों के साथ आती है, लेकिन यह तथ्य कि आप रनटाइम पर किसी ऑब्जेक्ट को क्वेरी कर रहे हैं समस्या नहीं है। आप देखेंगे कि मेरा क्या मतलब है।

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग आईएस-ए रिश्तों की धारणा पर बहुत अधिक झुक गई है, इसने यकीनन इस पर बहुत अधिक झुकाव किया है, जिससे दो प्रसिद्ध महत्वपूर्ण अवधारणाएं पैदा हुई हैं:

लेकिन मुझे लगता है कि आईएस-ए रिश्तों को देखने के लिए एक और अधिक कार्यात्मक-प्रोग्रामिंग-आधारित तरीका है जो शायद इन कठिनाइयों को नहीं करता है। सबसे पहले, हम अपने कार्यक्रम में घोड़ों और गेंडा को मॉडल करना चाहते हैं, इसलिए हम Horseएक Unicornप्रकार और एक प्रकार का होने जा रहे हैं । इन प्रकारों के मूल्य क्या हैं? खैर, मैं यह कहूँगा:

  1. इन प्रकारों के मूल्य घोड़ों और इकसिंगों (क्रमशः) के प्रतिनिधित्व या विवरण हैं;
  2. वे कर रहे हैं schematized , वे बहुत सख्त नियमों के अनुसार साथ बनाया कर रहे हैं प्रतिनिधित्व या वर्णन-रूप में नज़र आते नहीं मुक्त रूप।

यह स्पष्ट लग सकता है, लेकिन मुझे लगता है कि लोगों द्वारा सर्कल-एलिप्से समस्या जैसे मुद्दों में से एक को ध्यान में रखकर उन बिंदुओं पर ध्यान नहीं दिया गया है। हर वृत्त एक दीर्घवृत्त है, लेकिन इसका मतलब यह नहीं है कि किसी चक्र का प्रत्येक योजनाबद्ध विवरण स्वचालित रूप से एक अलग स्कीमा के अनुसार दीर्घवृत्त का एक योजनाबद्ध विवरण है। दूसरे शब्दों में, सिर्फ इसलिए कि एक वृत्त एक दीर्घवृत्त है इसका मतलब यह नहीं है कि एक एक Circleहै Ellipse, इसलिए बोलने के लिए। लेकिन इसका मतलब यह है कि:

  1. एक कुल फ़ंक्शन होता है जो किसी भी Circle(योजनाबद्ध सर्कल विवरण) को एक Ellipse(विभिन्न प्रकार के विवरण) में परिवर्तित करता है जो एक ही सर्कल का वर्णन करता है;
  2. एक आंशिक फ़ंक्शन होता है Ellipse, जो एक सर्कल का वर्णन करता है, और इसी रिटर्न देता है Circle

इसलिए, कार्यात्मक प्रोग्रामिंग शब्दों में, आपके Unicornप्रकार को बिल्कुल उप-प्रकार होने की आवश्यकता नहीं है Horse, आपको बस इन जैसे संचालन की आवश्यकता है:

-- Convert any unicorn-description of into a horse-description that
-- describes the same unicorns.
toHorse :: Unicorn -> Horse

-- If the horse described by the given horse-description is a unicorn,
-- then return a unicorn-description of that unicorn, otherwise return
-- nothing.
toUnicorn :: Horse -> Maybe Unicorn

और इसके toUnicornठीक विपरीत होना चाहिए toHorse:

toUnicorn (toHorse x) = Just x

हास्केल का Maybeप्रकार वह है जिसे अन्य भाषाएं "विकल्प" प्रकार कहती हैं। उदाहरण के लिए, जावा 8 Optional<Unicorn>प्रकार या तो Unicornकुछ भी नहीं है। ध्यान दें कि आपके दो विकल्प-एक अपवाद को फेंकने या "डिफ़ॉल्ट या जादू मूल्य" वापस करने के लिए - विकल्प के प्रकारों के समान।

इसलिए मूल रूप से जो मैंने यहां किया है वह अवधारणा आईएस-ए संबंध को प्रकारों और कार्यों के संदर्भ में फिर से संगठित करता है, बिना उपप्रकार या विरासत के उपयोग के। इससे मुझे क्या लेना देना है:

  1. आपके मॉडल को एक Horseप्रकार का होना चाहिए;
  2. इस Horseप्रकार को स्पष्ट रूप से निर्धारित करने के लिए पर्याप्त जानकारी को एन्कोड करने की आवश्यकता है कि क्या कोई मूल्य एक गेंडा का वर्णन करता है;
  3. Horseप्रकार के कुछ संचालन को उस जानकारी को उजागर करने की आवश्यकता होती है ताकि प्रकार के ग्राहक यह देख सकें कि क्या दिया Horseएक गेंडा है;
  4. प्रकार के ग्राहकों को Horseइन बाद के ऑपरेशनों का उपयोग रनवे पर यूनिकॉर्न और घोड़ों के बीच भेदभाव करने के लिए करना होगा।

तो यह मौलिक रूप से "प्रत्येक से पूछें Horseकि क्या यह एक गेंडा" मॉडल है। आप उस मॉडल से सावधान हैं, लेकिन मुझे गलत लगता है। यदि मैं आपको s की एक सूची देता हूं Horse, तो सभी प्रकार की गारंटी यह है कि सूची में बताई गई चीजें घोड़े हैं - इसलिए आप अनिवार्य रूप से, यह बताने के लिए रनटाइम पर कुछ करने की जरूरत है कि उनमें से कौन सी इकाइयां हैं। इसलिए ऐसा कुछ भी नहीं हो रहा है, मुझे लगता है - आपको उन कार्यों को लागू करने की आवश्यकता है जो आपके लिए ऐसा करेंगे।

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, ऐसा करने का परिचित तरीका निम्नलिखित है:

  • एक Horseप्रकार है;
  • के Unicornउपप्रकार के रूप में है Horse;
  • क्लाइंट-सुलभ ऑपरेशन के रूप में रनटाइम टाइप रिफ्लेक्शन का उपयोग करें जो यह बताता है कि क्या कोई दिया गया Horseहै Unicorn

इसकी एक बड़ी कमजोरी है, जब आप इसे "चीज़ बनाम विवरण" कोण से देखते हैं जो मैंने ऊपर प्रस्तुत किया है:

  • क्या होगा अगर आपके पास एक Horseउदाहरण है जो एक गेंडा का वर्णन करता है लेकिन एक Unicornउदाहरण नहीं है ?

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

तो मैं उस दृष्टिकोण के साथ जाऊँगा जहाँ एक स्पष्ट, गैर-डाउनकास्ट ऑपरेशन है जो Horseएस को Unicornएस में परिवर्तित करता है । यह या तो Horseप्रकार की एक विधि हो सकती है :

interface Horse {
    // ...
    Optional<Unicorn> toUnicorn();
}

... या यह एक बाहरी वस्तु हो सकती है (आपके "घोड़े पर अलग वस्तु जो आपको बताती है कि घोड़ा एक गेंडा है या नहीं"):

class HorseToUnicornCoercion {
    Optional<Unicorn> convert(Horse horse) {
       // ...
    }
}

इनमें से चुनाव इस बात का है कि आपका कार्यक्रम कैसे आयोजित किया जाता है - दोनों ही मामलों में, आपके पास Horse -> Maybe Unicornऊपर से मेरे ऑपरेशन के बराबर है , आप इसे अलग-अलग तरीकों से पैकेजिंग कर रहे हैं (यह माना जाएगा कि किस Horseप्रकार के ऑपरेशन के लिए आवश्यक रूप से लहर के प्रभाव होंगे अपने ग्राहकों को उजागर करने के लिए)।


-1

एक अन्य उत्तर में ओपी की टिप्पणी ने प्रश्न को स्पष्ट किया, मैंने सोचा

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

इस तरह से, मुझे लगता है कि हमें और जानकारी चाहिए। जवाब शायद कई बातों पर निर्भर करता है:

  • हमारी भाषा सुविधाएं। जैसे, मैं शायद रूबी और जावास्क्रिप्ट और जावा में इसे अलग तरीके से देखूंगा।
  • अवधारणाओं खुद को: क्या है एक घोड़ा और क्या है एक गेंडा? क्या डेटा प्रत्येक के साथ जुड़ा हुआ है? क्या वे सींग के अलावा बिल्कुल समान हैं, या क्या उनके पास अन्य मतभेद हैं?
  • हॉर्न लेंथ एवरेज लेने से अलग हम उन्हें कैसे इस्तेमाल कर रहे हैं? और झुंड के बारे में क्या? शायद हमें उन्हें भी मॉडल करना चाहिए? क्या हम उनका अन्यत्र उपयोग करते हैं? herd.averageHornLength()लगता है हमारे वैचारिक मॉडल से मेल खाता है।
  • घोड़े और गेंडा वस्तुओं को कैसे बनाया जा रहा है? क्या वह कोड हमारे रीफैक्टरिंग की सीमा में बदल रहा है?

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

ओपी, मुझे बताएं कि क्या मैं अभी भी गलत समझ रहा हूं ...


1
उचित अंक। समस्या को और अधिक अमूर्त बनने से रोकने के लिए हमें कुछ उचित धारणाएँ बनानी होंगी: 1) एक दृढ़ता से टाइप की गई भाषा 2) झुंड घोड़ों को एक प्रकार से रोकता है, संभवतः एक संग्रह के कारण 3) बतख टाइपिंग जैसी तकनीकों से संभवतः बचना चाहिए। । के रूप में क्या बदला जा सकता है, जरूरी नहीं कि कोई सीमाएं हों, लेकिन प्रत्येक प्रकार के परिवर्तन के अपने अनूठे परिणाम हैं ...
moarboilerplate

यदि झुंड एक प्रकार के घोड़ों को कसता है, तो हमारी एकमात्र पसंद वंशानुक्रम (उस विकल्प को पसंद नहीं है) या एक आवरण वस्तु (कहते हैं HerdMember) जिसे हम या तो एक घोड़े या गेंडा के साथ शुरू करते हैं (घोड़े को मुक्त करें और एक उप-प्रकार संबंध की आवश्यकता से मुक्त करें )। HerdMemberफिर isUnicorn()इसे लागू करने के लिए स्वतंत्र है हालांकि यह फिट दिखता है, और फ़िल्टरिंग समाधान जो मेरा सुझाव है वह निम्नानुसार है।
जोनाह

कुछ भाषाओं में, HornLength () को मिलाया जा सकता है, और यदि ऐसा है, तो यह एक वैध समाधान हो सकता है। हालाँकि, उन भाषाओं में जहाँ टाइपिंग कम लचीली होती है, आपको एक ही काम करने के लिए कुछ हैडिश तकनीकों का सहारा लेना पड़ता है, या आपको कुछ ऐसा करना पड़ता है जैसे कि घोड़े पर हॉर्नस्ट्रीम लगाया जाता है, जहाँ यह कोड में भ्रम पैदा कर सकता है क्योंकि एक घोड़ा नहीं करता है ' टी वैचारिक रूप से कोई सींग है। इसके अलावा, अगर गणितीय
संगणनाएँ करना

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

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

-2

एक विधि GetUnicorns () जो एक IEnumerable देता है, मेरे लिए सबसे सुंदर, लचीला और सार्वभौमिक समाधान लगता है। इस तरह से आप किसी भी (संयोजन) लक्षणों से निपट सकते हैं जो यह निर्धारित करते हैं कि एक घोड़ा एक गेंडा के रूप में पारित होगा, न केवल वर्ग प्रकार या किसी विशेष संपत्ति का मूल्य।


मैं इससे सहमत हु। मेसन व्हीलर के पास अपने उत्तर में भी एक अच्छा समाधान है, लेकिन अगर आपको अलग-अलग जगहों पर कई अलग-अलग कारणों से एक इकाइयां निकालने की आवश्यकता है, तो आपके कोड में बहुत सारे horses.ofType<Unicorn>...निर्माण होंगे। एक GetUnicornsसमारोह में एक-लाइनर होगा, लेकिन यह कॉलर के दृष्टिकोण से घोड़े / गेंडा संबंध में बदलाव के लिए आगे प्रतिरोधी होगा।
शौज

@ रियान यदि आप एक वापसी करते हैं IEnumerable<Horse>, हालांकि आपका गेंडा मानदंड एक ही स्थान पर है, तो यह समझाया जाता है, इसलिए आपके कॉल करने वालों को इस बारे में धारणा बनानी होगी कि उन्हें इकसिंगों की आवश्यकता क्यों है (मैं आज दिन का सूप ऑर्डर करके क्लैम चाउडर प्राप्त कर सकता हूं, लेकिन यह नहीं है ' टी का मतलब है कि मैं कल इसे प्राप्त करूंगा)। साथ ही, आपको हॉर्न के लिए एक डिफ़ॉल्ट मान को उजागर करना होगा Horse। यदि Unicornइसका अपना प्रकार है, तो आपको एक नया प्रकार बनाना होगा और प्रकार के मानचित्रण बनाए रखने होंगे, जो ओवरहेड को प्रस्तुत कर सकते हैं।
moarboilerplate

1
@Marboilerplate: हम समाधान के लिए उस सहायक के सभी पर विचार करते हैं। सौंदर्य हिस्सा यह है कि यह गेंडा के किसी भी कार्यान्वयन विवरण से स्वतंत्र है। चाहे आप किसी डेटा सदस्य, वर्ग या दिन के समय के आधार पर भेदभाव करते हों (वे घोड़े आधी रात को इकसिंगों में बदल सकते हैं यदि चंद्रमा मेरे सभी जानने के लिए सही है), समाधान खड़ा है, इंटरफ़ेस समान रहता है।
मार्टिन मेट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.