2012-06-11 11 views
16

मैं इस डिजाइन प्रश्न के लिए कोई सफलता के बिना एक साफ जवाब की तलाश में हूं। मुझे ".NET Framework design guidelines" में न तो "C# programing guidelines" में सहायता नहीं मिल सका। ,प्रतिनिधियों (लैम्ब्डा अभिव्यक्ति) बनाम इंटरफेस और अमूर्त वर्ग

1)

// This what I provide 
public abstract class AbstractDoSomething{ 
    public abstract SomeThing DoSomething(); 
} 

उपयोगकर्ता इस सार वर्ग को लागू करने की जरूरत है वे: मैं मूल रूप से एक API के रूप में एक पैटर्न का पर्दाफाश करने ताकि उपयोगकर्ताओं को परिभाषित करने और इस तरह मेरी ढांचे में अपने एल्गोरिदम को एकीकृत कर सकते है DoSomething विधि (है कि मैं अपने ढांचे के भीतर से फोन करके उपयोग कर सकते हैं)

2)

को लागू करना

मुझे पता चला कि यह भी प्रतिनिधियों का उपयोग करके प्राप्त कर सकते हैं:

public sealed class DoSomething{ 
    public String Id; 
    Func<SomeThing> DoSomething; 
} 

इस मामले में, यदि कोई उपयोगकर्ता केवल DoSomething वर्ग इस तरह से उपयोग कर सकते हैं:

DoSomething do = new DoSomething() 
{ 
    Id="ThisIsMyID", 
    DoSomething = (() => new Something()) 
} 

प्रश्न

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

संपादित

के मामले में: पंजीकरण इस तरह से किया जाता है (यह मानते हुए MyDoSomethingAbstractDoSomething लागू होता है:

MyFramework.AddDoSomething("DoSomethingIdentifier", new MyDoSomething()); 

के मामले में: पंजीकरण इस तरह से किया जाता है :

MyFramework.AddDoSomething(new DoSomething()); 
+0

उपयोगकर्ता आपके ढांचे के साथ सार DDSomethings कैसे पंजीकृत करता है? – dtb

+0

@dtb कृपया मेरा संपादन देखें (कोड को थोड़ा सा संशोधित करें) – GETah

उत्तर

15

इनमें से कौन सा विकल्प एक आसान, उपयोग करने योग्य और सबसे महत्वपूर्ण रूप से एक एपीआई के रूप में उजागर करने के लिए समझ में आता है?

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

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

कहा जा रहा है, आप एक प्रतिनिधि का उपयोग करने का तरीका अपनाने जा रहे हैं, मैं भी उपयोगकर्ता एक वर्ग बनाने नहीं होगा - जैसे एक विधि का उपयोग करें:

MyFramework.AddOperation("ThisIsMyID",() => DoFoo()); 

यह बनाता है मेरी राय में थोड़ा और स्पष्ट, कि आप सीधे सिस्टम में एक ऑपरेशन जोड़ रहे हैं। यह आपके सार्वजनिक एपीआई (DoSomething) में किसी अन्य प्रकार की आवश्यकता को पूरी तरह से समाप्त करता है, जो फिर से एपीआई को सरल बनाता है।

+0

+1। आपके उत्तर के लिए धन्यवाद। मेरे ढांचे के साथ सीधे 'Func' को पंजीकृत करने में समस्या यह है कि मैं भविष्य में उस कार्यक्षमता को विस्तारित नहीं कर सकता (' DoSomething' 'पर व्यवहार नहीं जोड़ सकता) – GETah

+0

@GETah जैसा कि मैंने अपनी पोस्ट में उल्लेख किया है, अगर आप चाहें तो व्यवहार जोड़ें, एक वर्ग शायद बेहतर है। (आभासी सदस्यों को जोड़ने पर वाक्य देखें ...) यही है, आईएमओ, प्रतिनिधियों के बजाय कक्षाओं का उपयोग करने का मुख्य लाभ। –

+0

ओह मैं देखता हूं। आपकी टिप्पणियों के लिए आभार। – GETah

6

मैं सार वर्ग/इंटरफेस है, तो साथ जाना होगा:

  • DoSomething आवश्यक है
  • DoSomething सामान्य रूप से वास्तव में बड़ी मिल जाएगा (ताकि DoSomething के कार्यान्वयन कई निजी/संरक्षित तरीकों में splited जा सकता है)

मैं प्रतिनिधियों के साथ जाना होगा अगर:

  • DoSomethi एनजी एक घटना (OnDoingSomething)
  • DoSomething वैकल्पिक (ताकि आप इसे नो-सेशन प्रतिनिधि के लिए डिफ़ॉल्ट) है
1

के रूप में सवालों के इन प्रकार के अधिकांश के लिए विशिष्ट है, मैं कहता हूँ "यह के रूप में इलाज किया जा सकता निर्भर करता है "। :)

लेकिन मुझे लगता है कि लैम्बडा बनाम अमूर्त वर्ग का उपयोग करने का कारण वास्तव में व्यवहार के लिए आता है। आम तौर पर, मुझे लगता है कि लैम्ब्डा को कॉलबैक प्रकार की कार्यक्षमता के रूप में उपयोग किया जा रहा है - जहां कुछ और होता है जब आप कुछ कस्टम होते हैं। मैं यह मेरा क्लाइंट-साइड कोड में बहुत कुछ कर: - कुछ डेटा वापस पाने - - अब है कि डेटा को संभालने के लिए तदनुसार

आप lambdas के साथ भी ऐसा कर सकते हैं मेरी कॉलबैक आह्वान - एक सेवा कॉल बनाने वे विशिष्ट हैं और बहुत विशिष्ट स्थितियों के लिए लक्षित हैं।

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

तो, मुझे लगता है कि अंगूठे का मेरा मोटा नियम है: - विशिष्ट कॉलबैक या साइड-इफेक्ट अनुकूलित व्यवहार के लिए लैम्बडा का उपयोग करें; - वस्तु व्यवहार अनुकूलन (या कम से कम वस्तु के प्राथमिक व्यवहार के बहुमत) के लिए एक तंत्र प्रदान करने के लिए सार कक्षाओं या इंटरफेस का उपयोग करें।

क्षमा करें मैं आपको एक स्पष्ट परिभाषा नहीं दे सकता, लेकिन मुझे आशा है कि इससे मदद मिलेगी। सौभाग्य!

1

कुछ बातों पर विचार करने के लिए:

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

उसी फ़ंक्शन के कितने अलग कार्यान्वयन की आवश्यकता होगी? यदि सिर्फ एक है, तो निष्ठा अच्छी है, लेकिन यदि आपके पास कई कार्यान्वयन हैं तो एक प्रतिनिधि ओवरहेड बचा सकता है।

यदि कई कार्यान्वयन हैं, तो क्या प्रोग्राम को उनके बीच स्विच करने की आवश्यकता होगी? या यह केवल एक ही कार्यान्वयन का उपयोग करेगा। यदि स्विचिंग की आवश्यकता है, तो प्रतिनिधियों को आसान हो सकता है, लेकिन मैं इसे सावधानी बरतूंगा, खासकर # 1 के उत्तर के आधार पर। रणनीति पैटर्न देखें।

यदि ओवरराइड को किसी भी संरक्षित सदस्यों तक पहुंच की आवश्यकता है, तो अंतहीनता। अगर यह केवल प्रकाशनों पर भरोसा कर सकता है, तो प्रतिनिधिमंडल।

अन्य विकल्प ईवेंट और एक्सटेंशन विधियां भी होंगी।

2

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

+1

आपके उत्तर के लिए धन्यवाद। एपीआई बनाने में समस्या दुर्भाग्य से आप क्या करना पसंद करते हैं लेकिन दूसरों को क्या करना पसंद है: पी – GETah

संबंधित मुद्दे