क्या मुझे अमूर्त या आभासी तरीकों का उपयोग करना चाहिए?


11

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

  • "अमूर्त" संस्करण का लाभ यह है कि यह संभवतः साफ दिखता है और व्युत्पन्न वर्ग को एक उम्मीद के मुताबिक सार्थक कार्यान्वयन के लिए मजबूर करता है।

  • "वर्चुअल" संस्करण का लाभ यह है कि इसे आसानी से अन्य मॉड्यूल द्वारा खींचा जा सकता है और परीक्षण के लिए उपयोग किया जाता है, जैसे कि अंतर्निहित संस्करण की तरह अंतर्निहित ढांचे का एक गुच्छा जोड़ने के बिना।

सार संस्करण:

public abstract class AbstractVersion
{
    public abstract ReturnType Method1();        
    public abstract ReturnType Method2();
             .
             .
    public abstract ReturnType MethodN();

    //////////////////////////////////////////////
    // Other class implementation stuff is here
    //////////////////////////////////////////////
}

वर्चुअल संस्करण:

public class VirtualVersion
{
    public virtual ReturnType Method1()
    {
        return ReturnType.NotImplemented;
    }

    public virtual ReturnType Method2()
    {
        return ReturnType.NotImplemented;
    }
             .
             .
    public virtual ReturnType MethodN()
    {
        return ReturnType.NotImplemented;
    }

    //////////////////////////////////////////////
    // Other class implementation stuff is here
    //////////////////////////////////////////////
}

हम ऐसा क्यों मान रहे हैं कि कोई इंटरफेस वांछनीय नहीं है?
एंथनी Pegram

आंशिक रूप से समस्या के बिना, यह कहना मुश्किल है कि एक दूसरे से बेहतर है।
संहितावाद

@ एंथनी: एक इंटरफ़ेस वांछनीय नहीं है क्योंकि उपयोगी कार्यक्षमता है जो इस वर्ग में भी जाएगी।
डंक

4
return ReturnType.NotImplemented? गंभीरता से? यदि आप संकलन समय पर अनइम्प्लीमेंट किए गए प्रकार को अस्वीकार नहीं कर सकते (आप कर सकते हैं, अमूर्त विधियों का उपयोग करें) कम से कम एक अपवाद फेंकें
Jan Hudec

3
@Dunk: यहाँ वे कर रहे हैं आवश्यक। रिटर्न मान अनियंत्रित हो जाएंगे।
Jan Hudec

जवाबों:


15

मेरा वोट, अगर मैं आपके सामान का उपभोग कर रहा था, तो वह अमूर्त तरीकों के लिए होगा। कि "जल्दी असफल हो जाता है।" सभी तरीकों को जोड़ने के लिए घोषणा के समय यह एक दर्द हो सकता है (हालांकि कोई भी सभ्य रीफ्रैक्टिंग टूल यह जल्दी करेगा), लेकिन कम से कम मुझे पता है कि समस्या तुरंत क्या है और इसे ठीक करें। मैं इसके बजाय 6 महीने और 12 लोगों के परिवर्तनों को बाद में देखने के लिए डीबग करना चाहता हूं कि हमें अचानक अपवाद क्यों नहीं मिल रहा है।


अनपेक्षित रूप से NotImplemented त्रुटि प्राप्त करने के बारे में अच्छी बात। जो अमूर्त पक्ष पर एक प्लस है, क्योंकि आपको रन-टाइम त्रुटि के बजाय एक संकलन-समय मिलेगा।
डंक

3
+1 - शुरुआती असफल होने के अलावा, विरासतकर्ता तुरंत देख सकते हैं कि उन्हें "इंप्लीमेंट एब्सट्रैक्ट क्लास" के माध्यम से किन तरीकों को लागू करने की ज़रूरत है, बजाय इसके कि वे क्या सोचते हैं और फिर रनटाइम में विफल हो रहे हैं।
तेलेस्टिन

मैंने इस जवाब को स्वीकार कर लिया क्योंकि संकलन के समय में विफल होना एक प्लस था जिसे मैं सूचीबद्ध करने में विफल रहा और आईडीई से ऑटो का उपयोग करने के संदर्भ के कारण तरीकों को जल्दी से लागू किया गया।
डंक

25

वर्चुअल संस्करण बग प्रोन और शब्दार्थ दोनों गलत है।

सार कह रहा है "यह विधि यहाँ लागू नहीं की गई है। आपको इस वर्ग के काम करने के लिए इसे लागू करना होगा"

वर्चुअल कह रहा है "मेरे पास एक डिफ़ॉल्ट कार्यान्वयन है लेकिन अगर आप की जरूरत है तो आप मुझे बदल सकते हैं"

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


3

यह आपकी कक्षा के उपयोग पर निर्भर करता है।

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

अन्यथा, मुझे लगता है कि आपको abstractतरीकों का उपयोग करना चाहिए ।

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


मैं यह नोट करूंगा कि "NotImplementedException" अक्सर चूक की त्रुटि को इंगित करता है, जबकि "NotSupportedException" एक ओवर्ट चॉइस को इंगित करता है। इसके अलावा, मैं सहमत हूं।
एंथनी पेग्राम

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

1

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

इस तरह इमेजिंग कोड:

public interface IVersion
{
    ReturnType Method1();        
    ReturnType Method2();
             .
             .
    ReturnType MethodN();
}

public abstract class AbstractVersion : IVersion
{
    public abstract ReturnType Method1();        
    public abstract ReturnType Method2();
             .
             .
    public abstract ReturnType MethodN();

    //////////////////////////////////////////////
    // Other class implementation stuff is here
    //////////////////////////////////////////////
}

ऐसा करने से इन समस्याओं का समाधान होता है:

  1. सभी कोड होने से जो AbstractVersion से प्राप्त वस्तुओं का उपयोग करता है, अब इसके बजाय IVersion इंटरफ़ेस प्राप्त करने के लिए लागू किया जा सकता है, इसका मतलब है कि वे अधिक आसानी से परीक्षण कर सकते हैं।

  2. आपके उत्पाद का रिलीज़ 2 तब आपके मौजूदा ग्राहकों के कोड को तोड़े बिना अतिरिक्त कार्यक्षमता प्रदान करने के लिए एक इंटरफ़ेस IVersion2 को लागू कर सकता है।

जैसे।

public interface IVersion
{
    ReturnType Method1();        
    ReturnType Method2();
             .
             .
    ReturnType MethodN();
}

public interface IVersion2
{
    ReturnType Method2_1();
}

public abstract class AbstractVersion : IVersion, IVersion2
{
    public abstract ReturnType Method1();        
    public abstract ReturnType Method2();
             .
             .
    public abstract ReturnType MethodN();
    public abstract ReturnType Method2_1();

    //////////////////////////////////////////////
    // Other class implementation stuff is here
    //////////////////////////////////////////////
}

यह भी निर्भरता उलटा के बारे में पढ़ने के लायक है, इस वर्ग को कठिन कोडित निर्भरता से रोकने के लिए जो प्रभावी इकाई परीक्षण को रोकते हैं।


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

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

-2

निर्भरता इंजेक्शन इंटरफेस पर निर्भर करता है। एक छोटा सा उदाहरण है। क्लास स्टूडेंट में CreateStudent नामक एक फंक्शन होता है जिसके लिए एक ऐसे पैरामीटर की आवश्यकता होती है जो "IReporting" (एक रिपोर्ट विधि के साथ) इंटरफ़ेस लागू करता है। यह एक छात्र बनाने के बाद इसे ठोस वर्ग पैरामीटर पर ReportAction कहता है। यदि हम एक ऐसे छात्र को बनाने के बाद एक ईमेल भेजने के लिए सिस्टम सेट अप करते हैं, जो हम एक ठोस वर्ग में भेजते हैं, जो अपने रिपोर्टेशन कार्यान्वयन में एक ईमेल भेजता है, या हम एक अन्य कंक्रीट क्लास में भेज सकते हैं जो अपने रिपोर्टएक्शन कार्यान्वयन में एक प्रिंटर को आउटपुट भेजता है। कोड पुन: उपयोग के लिए बढ़िया है।


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