कक्षा में बॉयलरप्लेट को कम करना जो संरचना के माध्यम से इंटरफेस को लागू करता है


11

मेरे पास एक वर्ग है: Aजो कई छोटी कक्षाओं का एक संयोजन है B, Cऔर D

B, C, और Dइंटरफेस को लागू IB, IC, और IDक्रमशः।

चूंकि Aसभी की कार्यक्षमता का समर्थन करता है B, Cऔर D, Aलागू करता है IB, ICऔर IDसाथ ही, लेकिन यह दुर्भाग्य से कार्यान्वयन में फिर से बहुत सारे मार्ग की ओर जाता हैA

इस तरह:

interface IB
{
    int Foo {get;}
}

public class B : IB
{
    public int Foo {get {return 5;}}
}

interface IC
{
    void Bar();
}

public class C : IC
{
    public void Bar()
    {
    }
}

interface ID
{
    string Bash{get; set;}
}

public class D: ID
{
    public string Bash {get;set;}
}

class A : IB, IC, ID
{
    private B b = new B();
    private C c = new C();
    private D d = new D();

    public int Foo {get {return b.Foo}}

    public A(string bash)
    {
        Bash = bash;
    }

    public void Bar()
    {
        c.Bar();
    }

    public string Bash
    {
         get {return d.Bash;}
         set {d.Bash = value;}
    }
}

क्या इस बायलरप्लेट पुनर्निर्देशन में से किसी से छुटकारा पाने का एक तरीका है A? B, Cऔर Dसभी अलग-अलग लेकिन सामान्य कार्यक्षमता को लागू करते हैं, और मुझे यह Aलागू करना पसंद है IB, ICऔर IDइसका मतलब है कि मैं Aअपने आप में उन इंटरफेस से मेल खाते हुए एक निर्भरता के रूप में पारित कर सकता हूं , और आंतरिक सहायक विधियों को उजागर नहीं करना है।


क्या आप इस बारे में कुछ कह सकते हैं कि आईबी, आईसी, आईडी को लागू करने के लिए आपको क्लास ए की आवश्यकता क्यों है? सिर्फ बीसीडी को जनता के सामने क्यों नहीं उजागर किया?
एसेन स्कोव पेडर्सन

1
मुझे लगता है कि Aकार्यान्वयन को प्राथमिकता देने के लिए मेरा प्राथमिक कारण है IB, ICऔर IDक्या यह उदाहरण के लिए Person.Walk()विरोध के रूप में लिखने के लिए अधिक समझदार लगता है Person.WalkHelper.Walk()
निक उदेल

जवाबों:


7

आप जिस चीज की तलाश कर रहे हैं उसे आमतौर पर मिक्सी कहा जाता है । अफसोस की बात है, C # उन लोगों का मूल समर्थन नहीं करता है।

कुछ वर्कअराउंड हैं: एक , दो , तीन और कई।

मैं वास्तव में पिछले एक की तरह हूं। बॉयलरप्लेट उत्पन्न करने के लिए स्वचालित रूप से उत्पन्न आंशिक वर्ग का उपयोग करने का विचार संभवतः निकटतम है आप वास्तव में अच्छा समाधान प्राप्त कर सकते हैं:

[pMixins] एक Visual Studio प्लग-इन है जो pMixin विशेषताओं से सजाए गए आंशिक वर्गों के लिए एक समाधान को स्कैन करता है। अपनी कक्षा को आंशिक रूप से चिह्नित करके, [pMixins] एक कोड-बैक फ़ाइल बना सकते हैं और आपकी कक्षा में अतिरिक्त सदस्य जोड़ सकते हैं


2

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

इसका उपयोग करने के लिए, पहले अपना इंटरफ़ेस IExampleऔर कार्यान्वयन बनाएं Example। फिर अपना नया वर्ग बनाएं Compositeऔर इसे उत्तराधिकार में लें IExample, लेकिन इंटरफ़ेस लागू न करें।

Exampleअपनी Compositeकक्षा में एक संपत्ति या प्रकार की फ़ील्ड जोड़ें , IExampleअपनी Compositeकक्षा फ़ाइल में टोकन पर त्वरित-क्रिया मेनू खोलें और "उदाहरण" के माध्यम से "इंटरफ़ेस लागू करें" चुनें, जहां इस मामले में 'उदाहरण' फ़ील्ड या संपत्ति का नाम है।

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


1

आपकी कक्षा बहुत अधिक कर रही है, इसीलिए आपको बहुत सारे बॉयलरप्लेट लागू करने होंगे। आप टिप्पणियों में कहते हैं:

Person.Walk () के विपरीत Person.WalkHelper.Walk () के रूप में व्यक्ति को लिखना अधिक समझदार लगता है

मैं असहमत हूं। चलने के कार्य में कई नियमों को शामिल करने की संभावना है और यह Personकक्षा में नहीं है - यह WalkingServiceएक walk(IWalkable)विधि के साथ एक वर्ग में है जहां व्यक्ति लागू होता है IWalkable

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


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

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

0

आप जिस चीज की तलाश कर रहे हैं वह कई विरासत है। हालाँकि, न तो C # है और न ही जावा।

आप ए से बी का विस्तार कर सकते हैं। यह बी के लिए एक निजी क्षेत्र की आवश्यकता को खत्म कर देगा और साथ ही पुनर्निर्देशित गोंद भी। लेकिन आप इसे केवल B, C या D में से किसी एक के लिए कर सकते हैं।

अब अगर आप C को B से विरासत में ले सकते हैं, और D को C से ले सकते हैं, तो आपके पास केवल A का विस्तार D ...;) होगा - बस हालांकि स्पष्ट होना है, मैं वास्तव में इस उदाहरण में प्रोत्साहित नहीं कर रहा हूँ क्योंकि वहाँ कोई संकेत नहीं है इसके लिए।

C ++ में आप B, C, और D से A वारिस प्राप्त कर सकेंगे।

लेकिन कई विरासत कार्यक्रमों को तर्क करने में कठिन बनाती हैं, और उनकी अपनी समस्याएं हैं; इसके अलावा, अक्सर इससे बचने का एक साफ तरीका है। फिर भी, कभी-कभी इसके बिना, किसी को बॉयलरप्लेट को दोहराने और ऑब्जेक्ट मॉडल के उजागर होने के बीच डिजाइन ट्रेडऑफ बनाने की आवश्यकता होती है।

ऐसा लगता है कि आप रचना और विरासत को मिलाने की कोशिश कर रहे हैं। यदि यह C ++ था, तो आप शुद्ध इनहेरिटेंस समाधान का उपयोग कर सकते हैं। लेकिन चूंकि यह नहीं है कि मैं रचना को अपनाने की सलाह दूंगा।


2
आप जावा और c # दोनों में इंटरफेस का उपयोग करके कई उत्तराधिकार प्राप्त कर सकते हैं, जैसे कि ऑप ने अपने उदाहरण कोड में किया है।
रॉबर्ट हार्वे

1
कुछ एक इंटरफ़ेस को कई वंशानुक्रम के अनुसार लागू करने पर विचार कर सकते हैं (जैसा कि C ++ में कहा गया है)। अन्य लोग असहमत होंगे, क्योंकि इंटरफेस अंतर्निहित उदाहरण विधियों को प्रस्तुत नहीं कर सकते हैं, जो कि यदि आपके पास कई विरासत हैं तो आपके पास क्या होगा। C # में, आप कई बेस क्लास का विस्तार नहीं कर सकते हैं, इसलिए, आप कई वर्गों से इंस्टेंस मेथड
इंप्लीमेंटेशन

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