स्थैतिक तरीकों को क्यों नहीं बदलना चाहिए?


13

इस सवाल के जवाब में , आम सहमति यह थी कि स्थिर तरीकों को ओवरराइड नहीं किया जाना चाहिए (और इस प्रकार C # में स्थिर कार्य आभासी या सार नहीं हो सकते हैं)। यह केवल C # में मामला नहीं है, हालांकि; जावा भी इसे मना करता है और C ++ इसे पसंद नहीं करता है। हालाँकि, मैं स्थैतिक कार्यों के कई उदाहरणों के बारे में सोच सकता हूं, जिन्हें मैं एक बच्चे की कक्षा (उदाहरण के लिए, कारखाने के तरीकों) में ओवरराइड करना चाहता हूं। सिद्धांत रूप में, उनके चारों ओर पाने के तरीके हैं, उनमें से कोई भी साफ या सरल नहीं है।

स्थैतिक कार्यों को क्यों नहीं बदलना चाहिए?


4
डेल्फी वर्ग विधियों का समर्थन करता है , जो स्थैतिक विधियों के समान हैं और उन्हें ओवरराइड किया जा सकता है। वे एक selfपॉइंटर पास करते हैं जो क्लास को इंगित करता है और क्लास के एक उदाहरण को नहीं।
CodeInChaos

स्थैतिक की एक परिभाषा है: परिवर्तन की कमी। मैं उत्सुक हूं कि आपने एक फ़ंक्शन को स्थिर क्यों बनाया जिसे आप ओवरराइड करना चाहते हैं।
जेएफओ

4
@ जेफ़ो: "स्टैटिक" की अंग्रेजी परिभाषा में स्थिर सदस्य कार्यों के अनूठे शब्दार्थों से कोई लेना-देना नहीं है।
ऑर्बिट

5
आपका प्रश्न है " एकल-आभासी प्रेषण के बजाय स्थिर तरीकों को सांख्यिकीय रूप से टाइप किए गए प्रेषण का उपयोग क्यों करना चाहिए ?" जब आप इस प्रश्न को इस तरह से उद्धृत करते हैं तो मुझे लगता है कि यह स्वयं उत्तर देता है।
एरिक लिपर्ट

1
@EricLippert इस सवाल को बेहतर ढंग से समझा जा सकता है कि "C # क्लास के तरीकों के बजाय स्टैटिक तरीके क्यों ऑफर करता है?", लेकिन यह अभी भी एक वैध सवाल है।
कोडइन्चौस

जवाबों:


13

स्थैतिक तरीकों के साथ, ओवरराइड तंत्र का उचित नियंत्रण प्रदान करने के लिए कोई वस्तु नहीं है।

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

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

(यह एक सही तंत्र नहीं है, क्योंकि कोई हमेशा उन क्षमताओं की पहचान कर सकता है जो समर्थित नहीं हैं, निश्चित रूप से, यही वजह है कि फैक्टरी विधि और निर्भरता इंजेक्शन जैसे पैटर्न शीर्ष पर स्तरित हैं।)

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

स्टैटिक्स के लिए ओवरराइड काफी हद तक अराजक होगा, और, इस तरह की चीजें पहले भी की जा चुकी हैं।

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

इस वजह से प्रोग्रामर के लिए अनकहा दुःख होता है क्योंकि ट्रैप पैचिंग की अनियंत्रित प्रकृति। जो कोई भी अंतिम रूप से जीता गया जाल को पैच करना चाहता था, भले ही वे नहीं चाहते थे। जाल का प्रत्येक पैचर एक प्रकार की मूल कॉल क्षमता के लिए पिछले जाल मूल्य को कैप्चर करेगा, जो बेहद नाजुक था। ट्रैप पैच को हटाते हुए, कहें कि जब आपको सिस्टम कॉल के बारे में जानने की कोई आवश्यकता नहीं थी, तो इसे खराब रूप माना गया क्योंकि आपके पास अपने पैच को हटाने के लिए वास्तव में आवश्यक जानकारी नहीं थी (यदि आपने ऐसा किया तो आप किसी भी अन्य पैच को अनचेक कर सकते हैं जो इसके बाद हुआ था आप)।

यह कहना नहीं है कि स्टैटिक्स के ओवरराइड के लिए एक तंत्र बनाना असंभव होगा, लेकिन मैं शायद इसके बजाय क्या करना पसंद करूंगा, स्थैतिक क्षेत्रों और स्थैतिक तरीकों को उदाहरण क्षेत्रों में और मेटाक्लासेस की आवृत्ति विधियों में बदल दें, ताकि सामान्य वस्तु ओरिएंटेशन तकनीक तब लागू होगी। ध्यान दें कि ऐसी प्रणालियाँ हैं जो ऐसा करती हैं: CSE 341: स्मालटाक क्लासेस और मेटाक्लासेस ; यह भी देखें: जावा के स्टैटिक के समतुल्य लघुतम क्या है?


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

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


अगर मैं सही ढंग से समझ रहा हूं: यह कोई बात नहीं है कि सैद्धांतिक रूप से आप ऐसा कुछ करना चाहते हैं या नहीं, लेकिन इससे अधिक प्रोग्रामेटिक रूप से, इसका कार्यान्वयन कठिन होगा और जरूरी नहीं कि उपयोगी हो?
PixelArtDragon

@ गौरन, मेरा ऐड देखिए।
एरिक इद्दत

1
मैं ऑर्डर देने का तर्क नहीं खरीदता; आपको उस विधि द्वारा प्रदान की जाने वाली विधि मिलती है जिसे आपने विधि कहा है (या पहला सुपरक्लास जो आपकी भाषा के चुने हुए रैखिक के अनुसार एक विधि प्रदान करता है)।
हॉब्स

1
@PierreArlaud: लेकिन this.instanceMethod()डायनेमिक रिज़ॉल्यूशन है, इसलिए यदि self.staticMethod()एक ही रिज़ॉल्यूशन, अर्थात् डायनेमिक है, तो यह एक स्थिर पद्धति नहीं होगी।
जॉर्ग डब्ल्यू मित्तग

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

9

ओवरराइडिंग वर्चुअल प्रेषण पर निर्भर करता है: आप thisकिस विधि को कॉल करने के लिए तय करने के लिए रनटाइम प्रकार के पैरामीटर का उपयोग करते हैं। एक स्थैतिक विधि का कोई thisपैरामीटर नहीं है, इसलिए प्रेषण पर कुछ भी नहीं है।

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

दुर्भाग्य से, न तो जेवीएम और न ही सीएलआर में कुछ भी तुलनीय है।


क्या यह उन भाषाओं का उपयोग selfकरता है जिनके पास कक्षाओं के रूप में वास्तविक, तात्कालिक वस्तुओं का उपयोग करने योग्य तरीकों के साथ होता है - स्मॉलटॉक ऑफ कोर्स, रूबी, डार्ट, ऑब्जेक्टिव सी, सेल्फ, पायथन? C ++ के बाद होने वाली भाषाओं की तुलना में, जहाँ कक्षाएँ प्रथम श्रेणी की वस्तुएँ नहीं हैं, भले ही वहाँ कुछ प्रतिबिंब हो?
जेरी 101101

बस स्पष्ट होने के लिए, आप कह रहे हैं कि पायथन या डेल्फी में, आप क्लास के तरीकों को ओवरराइड कर सकते हैं?
एरिक इद्दत

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

तो, इन भाषाओं में मेटाक्लासेस की कुछ प्रकार की धारणा प्रदान की जा रही है, नहीं?
एरिक इदत

1
@ एरिकईड पायथन में "सच" मेटाक्लासेस है। डेल्फी में, एक वर्ग संदर्भ एक विशेष डेटा प्रकार है, न कि अपने आप में एक वर्ग।
मेसन व्हीलर

3

तुम पूछो

स्थैतिक कार्यों को क्यों नहीं बदलना चाहिए?

मैं पूछता हूँ

ओवरराइड करने की इच्छा वाले कार्यों को स्थिर क्यों होना चाहिए?

कुछ भाषाएँ आपको स्थिर विधि से शो शुरू करने के लिए मजबूर करती हैं। लेकिन उसके बाद आप वास्तव में किसी भी अधिक स्थिर तरीकों के बिना एक महान कई समस्याओं को हल कर सकते हैं।

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

इन लोगों में से कोई भी गलत नहीं है।

यदि आपको इसकी आवश्यकता है कि यह अतिश्योक्तिपूर्ण हो जाए तो इसे स्थिर करना बंद कर दें। नथिंग्स टूटने जा रहे हैं क्योंकि आपके पास एक बेकार वस्तु है जो चारों ओर उड़ रही है।


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

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

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

1
"नथिंग्स टूटने जा रहे हैं क्योंकि आपके पास एक बेकार वस्तु है जो चारों ओर उड़ रही है।" ++++++
RubberDuck

@ TheodorosChatzigiannakis आप एक मजबूत तर्क देते हैं। अगर और कुछ नहीं तो आपने मुझे आश्वस्त किया है कि रेखा मेरे विचार के उद्देश्य को प्रेरित नहीं करती है। मैं वास्तव में लोगों को कुछ अधिक अभ्यस्त प्रथाओं को दूर करने की अनुमति देने की कोशिश कर रहा था जो वे आँख बंद करके स्थैतिक तरीकों से जोड़ते हैं। इसलिए मैंने अपडेट किया है। विचार?
कैंडिड_ऑरेंज सेप

2

स्थैतिक तरीकों को क्यों नहीं बदलना चाहिए?

यह "चाहिए" का सवाल नहीं है।

"ओवरराइडिंग" का अर्थ है " गतिशील रूप से प्रेषण "। "स्थैतिक विधि" का अर्थ है "सांख्यिकीय रूप से प्रेषण"। यदि कुछ स्थिर है, तो इसे ओवरराइड नहीं किया जा सकता है। अगर किसी चीज को ओवरराइड किया जा सकता है, तो वह स्थिर नहीं है।

आपका प्रश्न यह पूछने के लिए अधिक महत्वपूर्ण है: "ट्राइसाइकिल को चार पहियों के लिए सक्षम क्यों नहीं होना चाहिए?" "ट्राइसिकल" की परिभाषा है कि तीन पहिए हैं। यदि यह तिपहिया वाहन है, तो इसमें चार पहिए नहीं हो सकते हैं, यदि इसमें चार पहिए हैं, तो यह तिपहिया वाहन नहीं हो सकता है। इसी तरह, "स्थैतिक विधि" की परिभाषा यह है कि यह सांख्यिकीय रूप से भेजा जाता है। यदि यह एक स्थिर विधि है, तो इसे गतिशील रूप से नहीं भेजा जा सकता है, यदि इसे गतिशील रूप से भेजा जा सकता है, तो यह एक स्थिर विधि नहीं हो सकती है।

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


1
"परिभाषा के अनुसार" अच्छी तरह से।
कैंडिड_ऑरेंज 18

1

इस प्रकार C # में स्थिर कार्य आभासी या सार नहीं हो सकते हैं

C # में, आप हमेशा क्लास का उपयोग करते हुए स्थैतिक सदस्यों को बुलाते हैं, जैसे BaseClass.StaticMethod(), नहीं baseObject.StaticMethod()। तो आखिरकार, अगर आपको ChildClassविरासत में मिला है BaseClassऔर childObjectइसका उदाहरण है ChildClass, तो आप अपनी स्थैतिक विधि से कॉल नहीं कर पाएंगे childObject। आपको हमेशा स्पष्ट रूप से वास्तविक वर्ग का उपयोग करने की आवश्यकता होगी, इसलिए static virtualसिर्फ एक मतलब नहीं है।

आप जो कर सकते हैं, वही staticतरीका अपने बच्चे की कक्षा में फिर से परिभाषित करें , और newकीवर्ड का उपयोग करें ।

class BaseClass {
    public static int StaticMethod() { return 1; }
}

class ChildClass {
    public static new int StaticMethod() { return BaseClass.StaticMethod() + 2; }
}

int result;    
var baseObj = new BaseClass();
var childObj = new ChildClass();

result = BaseClass.StaticMethod();
result = baseObj.StaticMethod(); // DOES NOT COMPILE

result = ChildClass.StaticMethod();
result = childObj.StaticMethod(); // DOES NOT COMPILE

यदि कॉल करना संभव था baseObject.StaticMethod(), तो आपका प्रश्न समझ में आता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.