2010-09-14 17 views
6

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

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

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

इंटरफेस के कुछ उदाहरण मैं जानना चाहता हूं कि कार्यान्वयन का सबसे अच्छा तरीका ISerializable, IComparable, IComparable <>, ICloneable, IEnumerable <>, और इसी तरह से है। फ्रेमवर्क से सभी इंटरफेस यहां दिलचस्प हैं, इसलिए यह उन लोगों तक सीमित नहीं होना चाहिए जिन्हें मैंने ऊपर सूचीबद्ध किया है।

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

मैं, इन पैटर्न का एक अच्छा संग्रह प्राप्त करने के लिए आशा है कि के रूप में मुझे पता है कि वे बहुत मेरी कोड में सुधार लाने और इसे और अधिक सही कर सकते हैं और पालन सर्वोत्तम प्रथाओं

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

संपादित

Grzenios टिप्पणी पढ़ने के बाद, मैं भी हर किसी से आग्रह करता हूं संदर्भ पैटर्न के लिए लागू किया जाना चाहिए देने के लिए होगा। उदाहरण के लिए IDIsposable पैटर्न का पालन किया जाना चाहिए यदि आपके पास अपनी कक्षा के अंदर कुछ अप्रबंधित संसाधन हैं जिन्हें आपको निपटान करने की आवश्यकता है, और यदि नहीं, तो उन सभी ऑब्जेक्ट्स जिन्हें आप लागू करने के लिए आवश्यक हैं IDISposable स्वयं।

संपादित 2

मैं शायद यह अपने आप शुरू कर देना चाहिए, के बाद से मैं सवाल यहाँ से बाहर डाल दिया। तो मैं एक पैटर्न का वर्णन करूंगा जो मुझे अच्छी तरह से पता है, और यह IDISposable पैटर्न है।

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

तो पहले सबसे पहले। आपकी कक्षा को IDISposable इंटरफ़ेस को कार्यान्वित करना चाहिए, और आपको इंटरफ़ेस द्वारा सार्वजनिक निपटान विधि को परिभाषित करना होगा।यह विधि इस तरह दिखनी चाहिए:

public void Dispose() 
{ 
    Dispose(true); 
    GC.SuppressFinalize(this); 
} 

यह संरक्षित निपटान (बूल) विधि को कॉल करेगा जो वास्तविक सफाई का ख्याल रखता है।

private bool alreadyDisposed = false; 

GC.SuppressFinalize कचरा कलेक्टर बताता है कि यह आइटम भले ही यह एक है अंतिम रूप दिया जा की जरूरत नहीं है:

इसके अलावा, अगर वर्ग या निपटान किया जाता है नहीं अपनी कक्षा में एक vaiable इंगित करने के लिए शामिल finalizer।

फिर आपको संरक्षित निपटान विधि की आवश्यकता है। यह मामले में बजाय निजी की रक्षा की किसी भी व्युत्पन्न वर्ग इसे ओवरराइड करने की जरूरत है:

~SomeClass(){ 
    Dispose(false); 
} 

कुछ विधि हैं:

protected virtual void Dispose(bool isDisposing) 
{ 
    if (alreadyDisposed) 
    { 
    return; 
    } 
    if (isDisposing) 
    { 
    // free all managed resources here 
    } 
    // free all unmanaged resources here. 
    alreadyDisposed = true; 
} 

finalizer भी निपटान (bool) बुलाना चाहिए उपयोगकर्ता को साफ करने के भूल जाता है फ़ंक्शन करने के लिए एक डिस्पोजेड संसाधन की आवश्यकता होती है, इस तरह की फ़ंक्शन बनाएं:

public void SomeMethod() 
{ 
    if (alreadyDisposed) 
    throw new ObjectDisposedException("SomeClass", 
             "Called SomeMethod on Disposed object"); 
    // Method body goes here 
} 

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

+3

आईडीस्पोजेबल कार्यान्वयन पैटर्न केवल तभी मान्य होता है जब आपको * अंतिम * की आवश्यकता होती है। मामलों में आप वास्तविक जीवन में वास्तव में हानिकारक देखेंगे (क्योंकि जब आपको इसकी आवश्यकता नहीं होती है तो आपको अंतिम रूप देने वाला होता है, जिससे जीसी अधिक महंगा हो जाता है) – Grzenio

+0

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

उत्तर

3

आप डिजाइन पैटर्न के बारे में सीख रहे हैं, तब तक आप भी कुछ सामान्य विरोधी पैटर्न पर गौर करना चाहिए, तो आप एक विचार जहां पैटर्न से आता है मिलता है। IDisposable कुछ एंटी-पैटर्न का है, sequential coupling का एक मामूली संस्करण, जिसमें उपयोगकर्ता को निपटान करने की आवश्यकता होती है, और यदि वह भूल जाता है, तो आप बकवास में हैं। "डिस्पोजेबल पैटर्न" के मुख्य कारणों में से एक इस मुद्दे को ठीक करना है।

जहां भी संभव हो, एक पसंदीदा तकनीक (मेरा वैसे भी) किसी उपयोगकर्ता को आईडीआईस्पोजेबल ऑब्जेक्ट का पर्दाफाश नहीं करना है, लेकिन एक विधि का पर्दाफाश करें (उदाहरण के लिए इसे Using(...) पर कॉल करें), जो एक प्रतिनिधि लेता है जो सामान्य रूप से कोड निष्पादित करेगा आपके using(...) { } ब्लॉक में निहित है। यह विधि आपके निर्माण को निष्पादित कर सकती है, प्रतिनिधि को निष्पादित कर सकती है, फिर उपभोग किए गए संसाधनों का निपटान कर सकती है, और आईडीस्पोजेबल के साथ कम से कम 3 समस्याएं छोड़ सकती है: उपयोगकर्ता इसे कॉल करना भूल जाता है, उपयोगकर्ता इसे एक से अधिक बार कॉल करता है, और उपयोगकर्ता इसे भी कॉल करता है शुरुआती - जब आपको कोई IDISposable खुलासा नहीं होता है तो आपको उस बॉयलरप्लेट "डिस्पोजेबल पैटर्न" से परेशान करने की आवश्यकता नहीं है।

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

class MyFileStream { 
    FileStream fs; 
    private MyFileStream(string filename, FileMode mode) { 
     fs = new FileStream(filename, FileMode.Open); 
    } 
    private void Dispose() { 
     fs.Dispose(); 
    } 
    public static void Using(string filename, FileMode mode, Action<MyFileStream> use) { 
     MyFileStream mfs = new MyFileStream(filename, mode); 
     use(mfs); 
     mfs.Dispose(); 
    } 
    public void Read(...) { ... } 
} 

एक फोन करने वाले तो कह सकते हैं

var x = default(...); 
MyFileStream.Using("filename.txt", FileMode.Open, (stream) => { 
    x = stream.Read(...); 
}); 
Console.WriteLine(x); 

ध्यान दें कि यह वैसे भी बल्कि using() { } भाषा वाक्य रचना के समान है, हालांकि इस बार आप इसका इस्तेमाल करने के लिए मजबूर कर रहे हैं, और यह और भी प्रतिबंध लगाता है। कोई इस तरह संसाधनों को साफ़ करना नहीं भूल सकता है।

फिर भी, यह पैटर्न हमेशा उपयुक्त नहीं है क्योंकि आपको कभी-कभी केवल एक विधि कॉल से अधिक समय तक संसाधनों की आवश्यकता होती है, लेकिन यदि आपको इसका उपयोग करने का मौका मिलता है, तो ऐसा करें।

मैं वैसे भी विषय को पूरी तरह से चला गया हूं, इसलिए आप जो पूछ रहे थे उस पर वापस जाएं।

  • ICloneable का प्रयोग न करें - यह कैसे एक वस्तु क्लोन किया जा रहा है (गहरी या उथले), अगर आप इस तरह की बात की आवश्यकता होती है, बजाय अपने खुद के IDeepCloneable या IShallowCloneable इंटरफेस बनाने के बारे में कुछ नहीं कहते हैं।
  • IENumerable <> के लिए, यह एक दुर्लभ घटना है जिसे आपको स्वयं बनाने की आवश्यकता है, क्योंकि पहले से ही ढांचे में मौजूदा वर्गों का बड़ा संग्रह है, और आप आमतौर पर एक्सटेंशन विधियों को लागू करके अतिरिक्त सुविधाएं प्राप्त कर सकते हैं (जैसे LINQ, या स्वयं के रूप में, शक्तिशाली yield कीवर्ड का उपयोग करते हुए, जो पृष्ठभूमि में आपके लिए एक आईनेमेरेबल <> बनाएगा)।

मैं नहीं कहूंगा कि बाकी के लिए कोई विशिष्ट पैटर्न है, वे सुंदर आत्म व्याख्यात्मक हैं।

0

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

मैं उपरोक्त के साथ विघटन करता हूं। मैं कभी भी जीसी को साफ करने और ऑब्जेक्ट और संसाधन निपटान के बारे में निहित होने की अनुमति देने की सलाह नहीं देता हूं। यह नौकरानी के आस-पास आने और होटल में अपने गीले तौलिए लेने का इंतजार कर रहा है; यह अंत में होगा, लेकिन करने के लिए सही चीज उन्हें उठाओ और उन्हें खुद को लटकाओ।

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

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

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

मुझे लगता है कि आप कहां भ्रमित हो रहे हैं, .NET Framework में इंटरफेस को कार्यान्वित करने के बारे में है, लेकिन आपको इंटरफ़ेस की अवधारणा को देखने की आवश्यकता है, न केवल फ्रेमवर्क में उपलब्ध हैं। यदि आप वास्तव में उदाहरण देखना चाहते हैं कि .NET Framework में इंटरफ़ेस कैसे कार्यान्वित किए जाते हैं, तो एमएसडीएन या अन्य फ्रेमवर्क ऑब्जेक्ट्स को डीकंपाइल करें जो उन इंटरफ़ेस को कार्यान्वित करते हैं यह देखने के लिए कि माइक्रोसॉफ्ट उन्हें कैसे लागू करता है।

जैसे ही आप ओओडी में बढ़ते हैं, आप इंटरफेस के पीछे की शक्ति देखना शुरू कर देंगे और उन्हें अपनी कक्षाओं के लिए तैयार करना शुरू कर देंगे। उदाहरण के लिए कहें कि आपके पास इमाचिन नामक एक इंटरफेस है जिसे स्टेर्टइंजिन() कहा जाता है। हम केवल इंटरफेस के कार्यान्वयन को सभी विवरणों के को परिभाषित करना चाहते हैं; अनुसरण करने के लिए कोई 'पैटर्न' नहीं है और हम इंटरफ़ेस डिजाइनर को यह जानने की आवश्यकता नहीं है कि यह कैसे कार्यान्वित किया जाता है। एक कार के लिए शायद विधियों के कार्यान्वयन में "चाबियाँ प्राप्त करें, उन्हें इग्निशन में रखें, पार्क में डालें, ब्रेक पेडल दबाएं, इग्निशन चालू करें ..." हालांकि लॉनमोवर के लिए एक ही तरीके कार्यान्वयन है "मॉवर में प्राइम रखें कार्बोटेटर, क्लच खींचें, कॉर्ड खींचें ... "

तो आप देखते हैं कि आप .NET Framework में इंटरफ़ेस को देख सकते हैं और कार्यान्वयन के लिए एक निश्चित पैटर्न को कैसे लागू कर सकते हैं। कार्यान्वयन विवरण, पैटर्न इत्यादि कार्यान्वयन वर्ग तक हैं, और जब तक इंटरफेस के विवरण पर्याप्त हैं, तो यह महत्वपूर्ण है।

आशा है कि यह एक बिट में मदद करता है ...

+0

यह काफी गलत है। जीसी के साथ हस्तक्षेप सामान्य मामले में अक्षमता का कारण बनता है, क्योंकि .NET रनटाइम और सी # कंपाइलर दोनों को डिफ़ॉल्ट मामले के लिए अनुकूलित किया जाता है। इसलिए, जब तक आपके पास कोई अच्छा कारण न हो (जैसे अप्रबंधित संसाधनों को जारी करना), आमतौर पर वस्तुओं को निपटाने से बचने के लिए बेहतर होता है। – Gorpik

+0

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

+0

@ गोर्पिक - हमें असहमत होने के लिए सहमत होना होगा, क्योंकि निर्धारक वस्तु निपटान गलत नहीं है। ऑब्जेक्ट्स को इंस्टेंट करना और कॉल नहीं करना। उन पर निर्भर करें() और मेरे लिए दायरा को कम करना मैला प्रोग्रामिंग और अक्षम है। यह जीसी के साथ पूर्ण नहीं है, यह सिर्फ प्रक्रिया को गति देता है। यही कारण है कि आप इस ऑब्जेक्ट पर अंतिम विधि को कॉल न करने के लिए जीसी को ध्वजांकित करने के लिए निपटान विधि में 'जीसी। सुपरप्रेसफिनलाइज (मी)' कॉल करते हैं क्योंकि यह पहले से ही किया जा चुका है। – atconway

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

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