सिंगलटन या स्थिर वर्ग?

यह आलेख मुख्य रूप से उन डेवलपर्स के लिए उपयोगी होगा जो साक्षात्कार में खो जाते हैं जब वे सवाल सुनते हैं "एक सिंगलटन और एक स्थिर वर्ग के बीच मुख्य अंतर क्या हैं, और एक का उपयोग कब किया जाना चाहिए, और दूसरा कब है?" और यह उन डेवलपर्स के लिए निश्चित रूप से उपयोगी होगा जो शब्द "पैटर्न" पर, हतोत्साहित हो जाते हैं या खुद को व्यक्त करने से रोकने के लिए कहते हैं :)



एक स्थिर वर्ग क्या है?



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





सिंगलटन क्या है?



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



और अगर कोई अंतर नहीं है - तो अधिक उत्पादन क्यों करें?



तो इन दो संस्थाओं के बीच क्या अंतर है, और उन्हें कब इस्तेमाल किया जाना चाहिए? मुझे लगता है कि निम्नलिखित तालिका में यह वर्णन करना सबसे अच्छा है:

एकाकी वस्तु

स्थिर वर्ग

पहुंच बिंदुओं की संख्या

एक और केवल एक) एक्सेस प्वाइंट - इंस्टेंस स्टैटिक फील्ड

एन (सार्वजनिक वर्ग के सदस्यों और विधियों की संख्या पर निर्भर करता है)

वर्ग की विरासत

शायद, लेकिन हमेशा नहीं (नीचे उस पर अधिक)

असंभव - स्थैतिक वर्गों को त्वरित नहीं किया जा सकता है, क्योंकि आप स्थिर कक्षाओं की वस्तुओं के उदाहरण नहीं बना सकते हैं

इंटरफ़ेस वंशानुक्रम

शायद बिना किसी बंदिश के

उसी कारण से असंभव है कि वर्ग की विरासत संभव नहीं है

मापदंडों के रूप में पारित करने की क्षमता

संभवतः सिंगलटन एक वास्तविक वस्तु प्रदान करता है

गायब है

वस्तु जीवन भर की निगरानी

शायद - उदाहरण के लिए, आरंभीकरण में देरी (या मांग पर निर्माण )

उसी कारण से असंभव है कि वर्ग की विरासत संभव नहीं है

एक वर्ग को तत्काल करने के लिए एक अमूर्त कारखाने का उपयोग करना

शायद

एक उदाहरण बनाने की संभावना की कमी के कारण असंभव

क्रमबद्धता

शायद

उदाहरण के अभाव में लागू नहीं है।



ऊपर सूचीबद्ध मानदंडों पर अधिक विस्तार से विचार करें।



पहुंच बिंदुओं की संख्या


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



"कैनोनिकल" कार्यान्वयन में सिंगलटन:

public class Session { private static Session _instance; //   ... public static Session Instance { get { // ... return _instance; } } public IUser GetUser() { // ... } public bool IsSessionExpired() { // ... } public Guid SessionID { get { // ... } } }
      
      







स्थिर वर्ग:

 public static class Session { //   1 public static IUser GetUser() { // ... } //   2 public static bool IsSessionExpired() { // ... } // ... //   N public static Guid SessionID { get { // ... } } }
      
      







वर्ग की विरासत


स्थैतिक वर्गों की विरासत सरल है - यह केवल भाषा के स्तर पर समर्थित नहीं है। सिंगलटन के साथ, चीजें थोड़ी अधिक जटिल हैं। उपयोग में आसानी के लिए, कई डेवलपर्स अक्सर निम्नलिखित पैटर्न कार्यान्वयन का उपयोग करते हैं:

 public class Singleton<T> where T : class { private static T _instance; protected Singleton() { } private static T CreateInstance() { ConstructorInfo cInfo = typeof(T).GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]); return (T)cInfo.Invoke(null); } public static T Instance { get { if (_instance == null) { _instance = CreateInstance(); } return _instance; } } } public class Session : Singleton<Session> { public IUser GetUser() { // ... } public bool IsSessionExpired() { // ... } public Guid SessionID { get { // ... } } }
      
      





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

 public class Session : CoreObject { private Session() { } public static Session Instance { get { return Singleton<Session>.Instance; } } }
      
      





इंटरफ़ेस वंशानुक्रम


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

 //        ISession public class Session: CoreObject, ISession { private Session() { } public static Session Instance { get { return Singleton<Session>.Instance; } } } //                //     public class VpnSession : ISession { } public interface ISessionManager { ISession GetSession(Guid sessionID); //   ISession,     bool IsSessionExpired(ISession session); }
      
      







मापदंडों के रूप में पारित करने की क्षमता


स्थिर कक्षाओं के लिए, यह समर्थित नहीं है - आप केवल एक प्रकार पास कर सकते हैं, लेकिन अधिकांश स्थितियों में यह बेकार है, सिवाय जब प्रतिबिंब तंत्र का उपयोग किया जाता है। सिंगलटन अनिवार्य रूप से एक वस्तु का एक सामान्य उदाहरण है:

 // ... ISessionManager _sessionManager; // ... bool isExpired = _sessionManager.IsSessionExpired(Session.Instance);
      
      





वस्तु जीवन भर की निगरानी


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

 public class Singleton<T> where T : class { // ... public static T Instance { get { if (_instance == null) { //  " " _instance = CreateInstance(); } return _instance; } } }
      
      





आप एक सिंगलटन इंस्टेंस डिलीट ऑपरेशन भी जोड़ सकते हैं:

 public class Singleton<T> where T : class { // ... public static T Instance { // ... } //   ! public void RemoveInstance() { _instance = null; } }
      
      





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

 public class Singleton<T> where T : class { // ... public static T Instance { get { if (!IsAlive) { //    RemoveInstance(); } if (_instance == null) { //  " " _instance = CreateInstance(); } return _instance; } } private void RemoveInstance() { _instance = null; } }
      
      







एक वर्ग को तत्काल करने के लिए एक सार कारखाने का उपयोग करना


एक स्थिर वर्ग इस सुविधा का समर्थन नहीं करता है क्योंकि आप एक स्थिर वर्ग का उदाहरण नहीं बना सकते हैं। सिंगलटन के मामले में, सब कुछ सरल दिखता है:

 public interface IAbstractFactory { T Create<T>(); bool IsSupported<T>(); } public class Singleton<T> where T : class { private static T _instance; private static IAbstractFactory _factory; protected Singleton(IAbstractFactory factory) { _factory = factory; } public static T Instance { get { if (_instance == null) { _instance = _factory.Create<T>(); } return _instance; } } } //       public class Session : Singleton<Session> { protected Session() : base(new ConcreteFactory()) { } // ... }
      
      





सच है, सिंगलटन एकत्रीकरण के साथ वेरिएंट में, यह एक बहुत सुंदर और थोड़ा बोझिल समाधान लागू करने के लिए आवश्यक नहीं है:

 public class Session : CoreObject, ISession { private class SessionSingleton : Singleton<Session> { protected SessionSingleton() : base(new ConcreteFactory2()) { } } private Session() : base(new CoreContext()) { } public static Session Instance { get { return SessionSingleton.Instance; } } // ... }
      
      







क्रमबद्धता


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



तो क्या सिंगलटन या स्टेटिक वर्ग का उपयोग करें?



किसी भी मामले में, समाधान का विकल्प डेवलपर पर निर्भर करता है और कार्य की बारीकियों पर वह हल कर रहा है। लेकिन, किसी भी स्थिति में, निम्नलिखित निष्कर्ष निकाले जा सकते हैं:



एक सिंगलटन का उपयोग करना उचित है जब:



जब आप सिंगलटन के लिए सूचीबद्ध किसी भी स्क्रिप्ट को लागू करने की आवश्यकता नहीं है, तो स्थिर कक्षाओं का उपयोग करना उचित है । स्थैतिक वर्गों का मुख्य उद्देश्य अभी भी तार्किक रूप से समान विधियों, स्थिरांक, क्षेत्र और गुणों के समूहन में है। उदाहरण के लिए: System.Math , System.BitConverter , System.Buffer , System.Convert , आदि।



All Articles