2012-02-07 13 views
5

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

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

मेरे तुलना:

  1. BaseClass1/MyClass1:
    • चोर: IFoo से प्रत्येक लागू नहीं किया विधि के लिए BaseClass1 में आभासी सार बनाने के लिए है।
    • con: अतिरिक्त विधि लपेटें - रनटाइम पर मामूली उत्पादकता प्रभाव।
  2. BaseClass2/MyClass2:
    • चोर: कोई संकलक चेतावनी MyClass2 में Method2 का कोई कार्यान्वयन है। इसके बजाय रनटाइम अपवाद। खराब यूनिट परीक्षण कवरेज के साथ रिफैक्टरिंग संभावित रूप से कोड को अस्थिर कर सकता है।
    • con: बाल कक्षाओं से प्रत्यक्ष विधि कॉल को रोकने के लिए अतिरिक्त अप्रचलित निर्माण करना है।
    • con: Method2 बेसक्लास 1 के लिए सार्वजनिक है इसलिए यह अब कक्षा अनुबंध का हिस्सा है। IFoo के माध्यम से प्रत्यक्ष कॉल को रोकने के लिए "अप्रचलित" निर्माण करना होगा।
  3. BaseClass3/MyClass3:
    • समर्थक: (# 2 की तुलना में)। अधिक पठनीय। आप देखते हैं कि MyClass2.Method2 IFoo कार्यान्वयन है, न केवल कुछ ओवरराइड विधि।
public interface IFoo 
{ 
    void Method1(); 
    void Method2(); 
} 
public abstract class BaseClass1 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    void IFoo.Method2() 
    { 
     IFooMethod2(); 
    } 

    protected abstract void IFooMethod2(); 
} 

public class MyClass1 : BaseClass1 
{ 
    [Obsolete("Prohibited direct call from child classes. only inteface implementation")] 
    protected override void IFooMethod2() 
    { 
     //some implementation 
    } 
} 
public abstract class BaseClass2 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    [Obsolete("Prohibited direct call from child classes. only inteface implementation")] 
    public virtual void Method2() 
    { 
     throw new NotSupportedException(); 
    } 
} 

public abstract class MyClass2 : BaseClass2 
{ 
    public override void Method2() 
    { 
     //some implementation 
    } 
} 
public abstract class BaseClass3 : IFoo 
{ 
    void IFoo.Method1() 
    { 
     //some implementation 
    } 

    void IFoo.Method2() 
    { 
     throw new NotSupportedException(); 
    } 
} 

public abstract class MyClass3 : BaseClass3, IFoo 
{ 
    void IFoo.Method2() 
    { 
     //some implementation 
    } 
} 
+6

यह एक ** बहुत ** अजीब पैटर्न है जिसे आप कार्यान्वित करने का प्रयास कर रहे हैं। आपने कहा * "नेट नेट क्लास में आंशिक इंटरफ़ेस कार्यान्वयन की अनुमति नहीं देता है।" * - इसके लिए एक कारण है। क्लाइंट कोड की अपेक्षा कुछ ऐसा है जो ** इंटरफ़ेस लागू करता है **, आपको पता है, शायद ... ** इंटरफ़ेस को लागू करें **। पाठ्यक्रम के मामले में असमर्थित विधियों के लिए अपवाद फेंकना * बहुत * खराब कोड गंध है ... – Yuck

+0

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

+0

केवल MyClass1 _must_ पूरी तरह कार्यान्वित इंटरफ़ेस। और यह करता है। समस्या यह है कि कई बच्चे वर्ग हैं (मैंने पहले इसका उल्लेख नहीं किया था), प्रत्येक को IFoo लागू करना होगा। बेस क्लास के बिना आपको विधि 1 कार्यान्वयन की प्रतिलिपि बनाना/पेस्ट करना होगा, जो कि सभी बाल वर्गों के बराबर है।यही वह है जिसे मैं टालने की कोशिश कर रहा हूं। लेकिन विधि वर्ग कार्यान्वयन बाल वर्गों में अलग है, इसलिए मेरे पास केवल एक वर्ग नहीं है जो विधि 1 और विधि 2 दोनों लागू करता है। – user1194528

उत्तर

5

ठीक है, आप के रूप में BaseClass सार है निम्नलिखित की कोशिश कर सकते:

public interface IFoo 
{ 
    void Method1(); 

    void Method2(); 
} 

public abstract class BaseClass : IFoo 
{ 
    public void Method1() 
    { 
     // Common stuff for all BaseClassX classes 
    } 

    // Abstract method: it ensures IFoo is fully implemented 
    // by all classes that inherit from BaseClass, but doesn't provide 
    // any implementation right here. 
    public abstract void Method2(); 
} 

public class MyClass1 : BaseClass 
{ 
    public override void Method2() 
    { 
     // Specific stuff for MyClass1 
     Console.WriteLine("Class1"); 
    } 
} 

public class MyClass2 : BaseClass 
{ 
    public override void Method2() 
    { 
     // Specific stuff for MyClass2 
     Console.WriteLine("Class2"); 
    } 
} 

private static void Main(string[] args) 
{ 
    IFoo test1 = new MyClass1(); 
    IFoo test2 = new MyClass2(); 

    test1.Method2(); 
    test2.Method2(); 

    Console.ReadKey(); 
} 
+0

यह पहला संस्करण छोड़कर मेरा संस्करण # 2 है। अभी भी आवेदन करें: 1. बाल कक्षाओं से प्रत्यक्ष विधि कॉल को रोकने के लिए अतिरिक्त अप्रचलित निर्माण करना है। आपके मामले में कोई अप्रचलित नहीं है, इसलिए बाल वर्ग से प्रत्यक्ष कॉल संकलन समय चेतावनी उत्पन्न नहीं करेगा 2. विधि 2 बेस क्लास 1 के लिए सार्वजनिक है, इसलिए यह अब कक्षा अनुबंध का हिस्सा है। IFoo के माध्यम से प्रत्यक्ष कॉल को रोकने के लिए "अप्रचलित" निर्माण करना होगा। 3. कम पठनीय। आप नहीं देखते हैं कि विधि 2 IFoo कार्यान्वयन है। – user1194528

+0

प्रश्न के नीचे टिप्पणियां पढ़ना, यह समस्या को हल करने का सही तरीका प्रतीत होता है। 'बेसक्लास 'में' विधि 2() 'का एक अमूर्त कार्यान्वयन सुनिश्चित करता है कि' IFoo' पूरी तरह कार्यान्वित किया गया है, जबकि साथ ही 'बेसक्लास' से प्राप्त सभी वर्गों को 'विधि 2()' लागू करने के लिए मजबूर किया गया है। यह भी जोड़ा जा सकता है कि व्युत्पन्न कक्षाएं 'विधि 1() 'को ओवरराइड करने में सक्षम नहीं होंगी (लेकिन वे इसे _hide_ (' new' कीवर्ड का उपयोग करके) करने में सक्षम होंगे)। – Nailuj

+0

@ user1194528 उपरोक्त कोड के साथ आपकी वास्तविक समस्या क्या है? आप अप्रचलित टिप्पणियां क्यों रखना चाहते हैं? – ken2k

6

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

यहाँ कुछ आम समाधान

बुरा समाधान

  • एक अपवाद फेंक रहे हैं
  • घोषित यह रूप में अप्रचलित (यह डिजाइन शुरू से ही अच्छा) (NonImplementedException या NotSupportedException, sample देखें)

बेहतर समाधान

  • स्पष्ट इंटरफेस कार्यान्वयन, लेकिन आप अभी भी यह सबसे अच्छा समाधान को लागू (सिर्फ एक तरह से इसे छिपाने)

  • उपयोग इंटरफ़ेस अलगाव (पतले में अपने वसा इंटरफ़ेस विभाजित और अधिक प्रबंधनीय वाले)
+1

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

0

मैं सुझाव देता हूं कि अमूर्त बेस क्लास इंटरफेस को उन तरीकों से कार्यान्वित करे जो protected abstract विधियों को कॉल करते हैं, जैसा कि आपके पहले उदाहरण में दिखाया गया है, कुछ विधियों को लागू करने के तरीकों को छोड़कर ("सब कुछ IList में फेंकने के बाद" सभी विधियां वास्तव में "पैटर्न) काम करती हैं; वे protected virtual स्टब्स हो सकते हैं जो NotSupportedException फेंक देते हैं।

ध्यान दें कि यह बाल वर्ग पर निर्भर है कि इंटरफ़ेस के किसी विशेष सदस्य को एक समान नामित सार्वजनिक सदस्य (जो उपयुक्त सार सदस्य कह सकता है) के रूप में खुलासा करना है या नहीं।

वीबीनेट में उचित पैटर्न MustOverride Sub IFoo_Method1() Implements IFoo.Method1 जैसा कुछ होगा, जो अतिरिक्त फ़ंक्शन कॉल ओवरहेड से बच जाएगा, लेकिन सी # संरक्षित सदस्य के साथ इंटरफ़ेस को लागू करने का कोई माध्यम प्रदान नहीं करता है। किसी भी विधि के लिए स्पष्ट इंटरफ़ेस कार्यान्वयन का उपयोग करना जो कि बाल वर्ग में ओवरराइड हो सकता है, कुछ हद तक मुश्किल है, क्योंकि माता-पिता के कार्यान्वयन के लिए इंटरफ़ेस के बच्चे के पुन: कार्यान्वयन के लिए असंभव है।

+0

>> माता-पिता के कार्यान्वयन के लिए इंटरफ़ेस के बच्चे के पुन: कार्यान्वयन के लिए असंभव है। - अच्छी बात। इस परिप्रेक्ष्य से सभी विधियों को सुरक्षित के रूप में घोषित करना बेहतर है (+ उन लोगों के लिए सार, लागू नहीं) (केन 2 के संस्करण)। आपके विचारों के लिए धन्यवाद 2। अब मैं अधिक जानकारी प्राप्त कर सकता हूं। – user1194528

8

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

public interface IFoo 
{ 
    void Method1(); 
    void Method2(); 
} 

public abstract class BaseClass1 
{ 
    public void Method1() 
    { 
     //some implementation 
    } 
} 

public class MyClass1 : BaseClass1, IFoo 
{ 
    public void Method2() 
    { 
     //some implementation 
    } 
} 
संबंधित मुद्दे