2009-02-17 15 views
7

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

प्रश्न मूल रूप से है:

  • कैसे आप आईओसी कंटेनर के संबंध में ठोस प्रकार के साथ सौदा करते हैं? विशेष रूप से, उन्हें निपटाने के लिए कौन जिम्मेदार है, अगर उन्हें निपटान की आवश्यकता है, और यह ज्ञान कॉलिंग कोड पर कैसे प्रचारित हो जाता है?

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


संपादित: के बाद से यह दृष्टिकोण हम साथ समाप्त हो गया के सबसे करीब से एक है मैं @Chris Ballard द्वारा जवाब स्वीकार कर लिया।

public interface IService<T> : IDisposable 
    where T: class 
{ 
    T Instance { get; } 
    Boolean Success { get; } 
    String FailureMessage { get; } // in case Success=false 
} 

हम तो एक वस्तु इस इंटरफेस को लागू करने के लिए वापस दोनों .Resolve और .TryResolve से लौटने के लिए, तो हम क्या बुला कोड में मिलता है:

असल में, हम हमेशा एक प्रकार है कि इस तरह दिखता है वापसी हमेशा एक ही प्रकार।

अब, इस इंटरफ़ेस को लागू करने वाली वस्तु, IService<T> IDISposable है, और हमेशा का निपटान किया जाना चाहिए। यह प्रोग्रामर तक नहीं है जो यह तय करने के लिए एक सेवा का समाधान करता है कि IService<T> ऑब्जेक्ट का निपटान किया जाना चाहिए या नहीं।

हालांकि, और यह महत्वपूर्ण हिस्सा है, चाहे सेवा उदाहरण का निपटान किया जाना चाहिए या नहीं, यह ज्ञान IService<T> को लागू करने वाली वस्तु में बेक किया गया है, इसलिए यदि यह फैक्ट्री-स्कोप्ड सेवा है (यानी प्रत्येक कॉल को समाप्त करने के लिए समाप्त होता है एक नई सेवा उदाहरण के साथ), तो सेवा उदाहरण का निपटारा किया जाएगा जब IService<T> ऑब्जेक्ट का निपटारा किया जाता है।

इससे पूलिंग जैसी अन्य विशेष क्षेत्रों का समर्थन करना भी संभव हो गया। अब हम कह सकते हैं कि हम न्यूनतम 2 सेवा उदाहरण, अधिकतम 15, और आमतौर पर 5 चाहते हैं, जिसका अर्थ है कि प्रत्येक कॉल को। रिसोलव या तो उपलब्ध वस्तुओं के पूल से सेवा उदाहरण पुनर्प्राप्त करेगा, या एक नया निर्माण करेगा। और फिर, जब IService<T> ऑब्जेक्ट जिसमें पूल की गई सेवा है, का निपटारा किया जाता है, तो सेवा उदाहरण वापस अपने पूल में जारी किया जाता है।

ज़रूर, यह इस तरह से सभी कोड नज़र बनाया:

using (var service = ServiceContainer.Global.Resolve<ISomeService>()) 
{ 
    service.Instance.DoSomething(); 
} 

लेकिन यह एक साफ दृष्टिकोण है, और यह सेवा या उपयोग में ठोस वस्तु के प्रकार की परवाह किए बिना एक ही वाक्य रचना है, इसलिए हम चाहते हैं कि चुना के रूप में एक स्वीकार्य समाधान।


मूल प्रश्न भावी पीढ़ी के लिए, इस प्रकार


घना प्रश्न यहाँ आता है:

हम एक आईओसी कंटेनर है कि हम का उपयोग किया है, और हाल ही में हम क्या मात्रा की खोज की एक समस्या के लिए।

गैर आईओसी कोड में, जब हम उपयोग करने के लिए, मान लें एक फ़ाइल चाहता था, हम इस तरह एक वर्ग का प्रयोग किया:

using (Stream stream = new FileStream(...)) 
{ 
    ... 
} 

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

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

using (BinaryDataProvider provider = new BinaryDataProvider(...)) 
{ 
    ... 
} 

इतना नहीं बदलता है। यह ज्ञान कि कक्षा आईडीस्पोज़ेबल लागू करती है, अभी भी कोई सवाल नहीं है, हमें निपटान को कॉल करने की आवश्यकता है।

लेकिन, मान लीजिए कि हमारे पास कक्षाएं हैं जो डेटा प्रदान करती हैं जो अभी इस तरह के सीमित संसाधनों का उपयोग नहीं करती है।

ऊपर कोड तो के रूप में लिखा जा सकता है:

BinaryDataProvider provider = new BinaryDataProvider(); 
... 

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

कोड तो होगा:

IBinaryDataProvider provider = 
    ServiceContainer.Global.Resolve<IBinaryDataProvider>(); 
... 

ध्यान दें कि मुझे लगता है कि हम उपलब्ध के माध्यम से वस्तु का उपयोग कर सकते एक स्वतंत्र इंटरफेस है।

उपर्युक्त परिवर्तन के साथ, क्या होगा यदि हम बाद में उस ऑब्जेक्ट का उपयोग करना चाहते हैं जिसका वास्तव में निपटान किया जाना चाहिए? उस इंटरफ़ेस को हल करने वाले मौजूदा कोड में से कोई भी ऑब्जेक्ट का निपटान करने के लिए लिखा गया है, तो अब क्या?

जिस तरह से हम यह देखते हैं, हम एक समाधान लेने के लिए है:

  • क्रम जाँच लागू की जाँच करता है कि है कि एक ठोस प्रकार है कि पंजीकृत किया जा रहा लागू करता है, तो IDisposable, आवश्यकता है कि इंटरफेस यह भी औजार के माध्यम से सामने आ रहा है IDisposable।यह एक अच्छा समाधान
  • Enfore इंटरफेस पर एक बाधा नहीं किया जा रहा है वे हमेशा IDisposable से विरासत चाहिए, ताकि भविष्य प्रूफ
  • क्रम कि कोई ठोस प्रकार IDisposable हो सकता है लागू होने के लिए के बाद से इस विशेष रूप से नहीं है आईओसी कंटेनर
  • का उपयोग करके कोड द्वारा संभाला गया यह जांचने के लिए प्रोग्रामर को छोड़ दें कि ऑब्जेक्ट लागू करने योग्य है और "सही चीज़ करें"?
  • क्या अन्य लोग हैं?

इसके अलावा, रचनाकारों में वस्तुओं को इंजेक्शन देने के बारे में क्या? हमारे कंटेनर, और कुछ अन्य कंटेनर जिन्हें हमने देखा है, एक ठोस प्रकार के कन्स्ट्रक्टर को पैरामीटर में ताजा ऑब्जेक्ट इंजेक्शन करने में सक्षम है। उदाहरण के लिए, यदि हमारे BinaryDataProvider को उस ऑब्जेक्ट की आवश्यकता है जो ILogging इंटरफ़ेस लागू करता है, यदि हम इन ऑब्जेक्ट्स पर आईडीआईज़ेस-"क्षमता" को लागू करते हैं, तो किसकी जिम्मेदारी लॉगिंग ऑब्जेक्ट का निपटान करना है?

आपको क्या लगता है? मुझे राय चाहिए, अच्छा और बुरा।

उत्तर

2

(अस्वीकरण: मैं जावा सामान के आधार पर इस का जवाब दे रहा हूँ हालांकि मैं कार्यक्रम सी # मैं सी # में कुछ भी प्रॉक्सी नहीं किया है, लेकिन मैं जानता हूँ कि यह संभव है जावा शब्दावली के बारे में क्षमा करें।।)

आप आईओसी दे सकता है फ्रेमवर्क यह देखने के लिए ऑब्जेक्ट का निर्माण कर रहा है कि यह पहचान योग्य है या नहीं। यदि नहीं, तो आप आईओसी फ्रेमवर्क क्लाइंट कोड को प्रदान करने वाली वास्तविक ऑब्जेक्ट को लपेटने के लिए गतिशील प्रॉक्सी का उपयोग कर सकते हैं। यह गतिशील प्रॉक्सी IDISposable लागू कर सकता है, ताकि आप हमेशा क्लाइंट को एक आईडीस्पोज़ेबल प्रदान कर सकें। जब तक आप इंटरफेस के साथ काम कर रहे हैं जो काफी सरल होना चाहिए?

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

+0

अच्छा, ऐसा लगता है कि "हमेशा आईओसी कंटेनर से एक आईडीस्पोजेबल ऑब्जेक्ट लौटाएं" और फिर सबसे आसान समाधान यह है कि ठोस प्रकारों के लिए मानदंड बनाना। उस इंटरफ़ेस का कार्यान्वयन निश्चित रूप से खाली छोड़ा जा सकता है, इसलिए बहुत अधिक ओवरहेड कोड-वार नहीं है, केवल एक विधि है। –

+0

हाँ मुझे लगता है कि थोड़ा अंतर है। मुझे लगता है कि मूल समस्या यह है कि आपको क्लाइंट कोड पर ऑब्जेक्ट की डिस्पोजेबिलिटी को संवाद करने की आवश्यकता है, इसलिए मुझे लगता है कि थोड़ी उम्मीद है;) – krosenvold

+0

मैं डिस्पोजेबल ऑब्जेक्ट्स का समर्थन नहीं करता हूं। – krosenvold

3

एक विकल्प, एक कारखाने पैटर्न के साथ जाने के लिए हो सकता है इतना है कि आईओसी कंटेनर कभी नहीं की जरूरत से सीधे बनाया खुद वस्तुओं निपटारा करने के लिए, जैसे

IBinaryDataProviderFactory factory = 
    ServiceContainer.Global.Resolve<IBinaryDataProviderFactory>(); 
using(IBinaryDataProvider provider = factory.CreateProvider()) 
{ 
    ... 
} 

नकारात्मक जटिलता जोड़ दिया जाता है, लेकिन इसका मतलब यह है कि कंटेनर ऐसा कुछ भी नहीं बनाता है जिसे डेवलपर को निपटाना है - यह हमेशा स्पष्ट कोड होता है जो यह करता है।

यदि आप वास्तव में इसे स्पष्ट करना चाहते हैं, तो कारखाने विधि को CreateDisposableProvider() जैसे कुछ नाम दिया जा सकता है।

+0

आईओसी कंटेनर का पूरा बिंदु यह है कि बाद में, कॉन्फ़िगरेशन के माध्यम से, मैं एक अलग वस्तु वापस कर सकता हूं। आपके उदाहरण में, इस तरह की हर वस्तु को IDISposable लागू करना होगा। मेरा सवाल है: क्या यह उन वस्तुओं के लिए मानदंड है? क्या मैं कुछ मानदंड निर्दिष्ट कर सकता हूं, या यह प्रति इंटरफ़ेस है? भविष्य दृढ़? –

+0

इस उदाहरण में मैं कारखाने के विभिन्न कार्यान्वयन वापस कर सकता हूं, लेकिन प्रत्येक को एक प्रदाता बनाना होगा जो आईडीस्पोज़ेबल लागू करता है। यह आदर्श नहीं है लेकिन कम से कम आपको अर्थशास्त्र के बारे में एक सुराग देता है। शायद यह सवाल नहीं है जिसे आप पूछ रहे थे? –

+0

नहीं, मेरा सवाल है: क्या मैं, आईओसी कंटेनर के माध्यम से, यह लागू कर सकता हूं कि ऐसे सभी इंटरफेस और ठोस प्रकार IDISposable लागू करें, या क्या मुझे इसे उपयोगकर्ता के लिए एक अभ्यास के रूप में छोड़ देना चाहिए? –

1

आप वास्तव में बहुत गंदे समाधान के साथ आए: आपके IService अनुबंध SRP का उल्लंघन करता है, जो एक बड़ा नंबर नहीं है।

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

दूसरी तरफ प्रोटोटाइप का प्रबंधन पूरी तरह से कॉलिंग कोड की ज़िम्मेदारी है।

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