क्या एक सार वर्ग में सभी सार्वजनिक तरीकों को आभासी चिह्नित किया जाना चाहिए?


12

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

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

हालाँकि, मैं पूछना चाहता था कि ऐसा कुछ है जो मैं सोच नहीं सकता। क्या एक सार वर्ग के भीतर सभी सार्वजनिक तरीकों को आभासी बनाया जाना चाहिए?


इससे मदद मिल सकती है: stackoverflow.com/questions/391483/…
NoChance

1
शायद आपको इस बात पर ध्यान देना चाहिए कि C # में डिफ़ॉल्ट आभासी क्यों नहीं है, लेकिन जावा में है। कारण शायद आप जवाब में कुछ अंतर्दृष्टि दे देंगे।
डैनियल लिटिल

जवाबों:


9

हालांकि, जब तक आप भरोसा करते हैं कि लिस्कोव के प्रतिस्थापन सिद्धांत का पालन किया जाएगा, तब आप इसे ओवरराइड करने की अनुमति क्यों नहीं देंगे?

उदाहरण के लिए, क्योंकि मैं चाहता हूं कि एल्गोरिथ्म के कंकाल को ठीक किया जाए, और केवल विशिष्ट हिस्सों को उपवर्गों द्वारा परिभाषित (पुनः) होने दें। इसे व्यापक रूप से टेम्पलेट विधि पैटर्न (मेरे द्वारा नीचे जोर) के रूप में जाना जाता है :

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

अपडेट करें

जिन परियोजनाओं पर मैं काम कर रहा हूँ, उनके कुछ ठोस उदाहरण:

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

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

ये केवल सबसे हालिया उदाहरण हैं जो मेरे दिमाग में आते हैं। मैं अब तक काम कर रही लगभग हर परियोजना से अधिक मामलों का हवाला दे सकता हूं।


बस GoF को उद्धृत करना एक उत्तर नहीं है। आपको ऐसा करने के लिए वास्तविक कारण देने की आवश्यकता होगी।
डेडजैम

@DeadMG, मैं अपने करियर के दौरान नियमित रूप से टेम्प्लेट मेथड का उपयोग करता रहा हूं, इसलिए मुझे लगा कि यह स्पष्ट है कि यह एक बहुत ही व्यावहारिक और उपयोगी पैटर्न है (जैसा कि अधिकांश GoF पैटर्न हैं ... ये सैद्धांतिक शैक्षणिक अभ्यास नहीं हैं, लेकिन एकत्र किए गए हैं वास्तविक दुनिया के अनुभव से)। लेकिन जाहिरा तौर पर हर कोई इससे सहमत नहीं है ... इसलिए मैं अपने जवाब में कुछ ठोस उदाहरण जोड़ता हूं।
पेटर टॉर्क

2

यह पूरी तरह से उचित है, और कभी-कभी एक सार आधार वर्ग में गैर-आभासी तरीकों के लिए वांछनीय है; सिर्फ इसलिए कि यह एक अमूर्त वर्ग है, इसका मतलब यह नहीं है कि इसका हर हिस्सा बहुउपयोगी होना चाहिए।

उदाहरण के लिए, आप 'नॉन वर्चुअल पॉलीमॉर्फिज्म' मुहावरे का उपयोग करना चाह सकते हैं, जिससे किसी फ़ंक्शन को गैर-वर्चुअल सदस्य फ़ंक्शन से बहुरूपता कहा जाता है, ताकि यह सुनिश्चित किया जा सके कि वर्चुअल फ़ंक्शन को कॉल करने से पहले कुछ पूर्व शर्त या पोस्टकंडिशन मिलते हैं।

class MyAbstractBaseClass
{
protected:
    virtual void OverrideMe() = 0;
public:
    void CallMeFirst();

    void CallMe()
    {
        CallMeFirst();
        OverrideMe();
    }
};

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

2

कक्षा को अमूर्त बनाने के लिए, एक कक्षा के लिए एक वर्चुअल विधि होना पर्याप्त है। आप उन तरीकों पर ध्यान देना चाहते हैं जो आप आभासी चाहते हैं और जो नहीं, जिस प्रकार के बहुरूपता के अनुसार आप उपयोग करने की योजना बना रहे हैं।


1

अपने आप से पूछें कि एक अमूर्त वर्ग में गैर-आभासी पद्धति का क्या उपयोग है। इस तरह की विधि को इसे उपयोगी बनाने के लिए एक कार्यान्वयन करना होगा। लेकिन अगर कक्षा में एक कार्यान्वयन है, तो क्या इसे अभी भी एक सार वर्ग कहा जा सकता है? भले ही भाषा / संकलक इसे अनुमति देता है, क्या यह समझ में आता है? व्यक्तिगत रूप से, मुझे ऐसा नहीं लगता। आपके पास अमूर्त तरीकों के साथ एक सामान्य वर्ग होगा जिसे वंशजों को लागू करने की उम्मीद है।

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


2
मुझे लगता है कि एक सार वर्ग के लिए यह सही अर्थ है कि कुछ सार विधियां हैं, कुछ आभासी तरीके हैं और कुछ गैर-आभासी तरीके हैं। मुझे लगता है कि यह हमेशा इस बात पर निर्भर करता है कि आप वास्तव में क्या करना चाहते हैं।
20

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

@JustinPihony: धन्यवाद। डेल्फी में, जब आप एक विधि सार को चिह्नित करते हैं, तो संकलक शिकायत करेगा यदि आप इसके लिए एक कार्यान्वयन प्रदान करते हैं। दिलचस्प है कि विभिन्न भाषाएं अवधारणाओं को अलग तरीके से कैसे लागू करती हैं और इस प्रकार उनके उपयोगकर्ताओं में अलग-अलग अपेक्षाएं पैदा करती हैं।
मार्जन वेनमा

@ शविक: हाँ, यह सही अर्थ है, मैं इसे एक सार वर्ग नहीं कहूंगा, लेकिन अमूर्त तरीकों के साथ एक वर्ग ... लेकिन मुझे लगता है कि यह सिर्फ मेरी व्याख्या हो सकती है।
मार्जन वेनेमा

@MarjanVenema, लेकिन यह शब्दावली C # का उपयोग नहीं करता है। यदि आप किसी कक्षा में कोई विधि abstractअंकित करते हैं, तो आपको पूरी कक्षा को भी चिन्हित करना चाहिए abstract
12

0

हालांकि, जब तक आप भरोसा करते हैं कि लिस्कोव के प्रतिस्थापन सिद्धांत का पालन किया जाएगा, तब तक> आप इसे अमान्य क्यों नहीं होने देंगे?

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

व्यक्तिगत रूप से, मैं अक्सर ऐसी विधि अधिभार बनाऊंगा जो सुविधा के लिए मौजूद है न कि आभासी ताकि कक्षा के उपयोगकर्ता लगातार चूक कर सकें और कार्यान्वयनकर्ता उस निहित व्यवहार को तोड़ने की गलती करने में भी सक्षम न हों।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.