एक वर्ग पर 'अंतिम' का उपयोग वास्तव में इतना बुरा क्यों है?


34

मैं एक PHP OOP विरासत वेबसाइट refactoring कर रहा हूँ।

मुझे कक्षाओं में "अंतिम" का उपयोग शुरू करने की बहुत लालच है " make it explicit that the class is currently not extended by anything"। यह बहुत समय बचा सकता है यदि मैं एक कक्षा में आता हूं और मैं सोच रहा हूं कि क्या मैं किसी protectedसंपत्ति या विधि का नाम बदल / हटा सकता हूं / संशोधित कर सकता हूं । अगर मैं वास्तव में एक वर्ग का विस्तार करना चाहता हूं तो मैं अंतिम कीवर्ड को निकालने के लिए अनलॉक कर सकता हूं ।

Ie यदि मैं एक ऐसे वर्ग में आता हूं जिसमें कोई बाल वर्ग नहीं है तो मैं उस ज्ञान को कक्षा को अंतिम रूप देते हुए रिकॉर्ड कर सकता हूं। अगली बार जब मैं आता हूं तो मुझे यह देखने के लिए कोडबेस को दोबारा नहीं खोजना पड़ेगा कि इसमें बच्चे हैं या नहीं। इस प्रकार रिफ्लेक्टरिंग के दौरान समय की बचत होती है।

यह सब एक समझदार समय बचाने के विचार की तरह लगता है .... लेकिन मैंने अक्सर पढ़ा है कि कक्षाओं को केवल दुर्लभ / विशेष अवसरों पर 'अंतिम' बनाया जाना चाहिए।

शायद यह मॉक ऑब्जेक्ट क्रिएशन को बढ़ाता है या इसके अन्य दुष्प्रभाव हैं जो मैं नहीं सोच रहा हूं।

मुझे किसकी याद आ रही है?


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

उदाहरण के लिए, MbUnit .net यूनिट परीक्षण के लिए एक खुला ढांचा है, और MsTest ain't (आश्चर्य चकित)। परिणाम के रूप में, आपको 5k से MSFT के लिए खोलना होगा क्योंकि आप MSFT तरीके से कुछ परीक्षण चलाना चाहते हैं। अन्य परीक्षण धावक एमएसटीएफ द्वारा उपयोग किए जाने वाले अंतिम वर्गों - सभी के साथ एमएसटीईएस के साथ बनाया गया परीक्षण डीएल नहीं चला सकते हैं।
जॉब

3
विषय के बारे में कुछ ब्लॉग पोस्ट: फाइनल क्लासेस: एक्सटेंशन के लिए ओपन, इनहेरिटेंस के लिए बंद (मई 2014, मैथियास वेरेस द्वारा)
हैक्रे

अच्छा लेख। यह इस बारे में मेरे विचार बोलता है। मुझे उन एनोटेशन के बारे में पता नहीं था इसलिए यह आसान था। चीयर्स।
JW01

"PHP 5 अंतिम कीवर्ड का परिचय देता है, जो बाल कक्षाओं को अंतिम रूप से परिभाषा को उपसर्ग करने से रोकता है। यदि वर्ग को ही अंतिम रूप से परिभाषित किया जा रहा है तो इसे बढ़ाया नहीं जा सकता है।" php.net/manual/en/language.oop5.final.php यह बिल्कुल भी बुरा नहीं है।
काला

जवाबों:


54

मैंने अक्सर पढ़ा है कि दुर्लभ / विशेष अवसरों पर कक्षाओं को केवल 'अंतिम' बनाया जाना चाहिए।

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

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

शायद यह मॉक ऑब्जेक्ट निर्माण पर शिकंजा…

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


1
1+: चूंकि यह मजाक उड़ाता है; प्रत्येक "अंतिम" वर्ग के लिए इंटरफेस या अमूर्त कक्षाएं बनाने पर विचार करें।
स्पूइक जूल

ठीक है कि काम करता है में एक स्पैनर डालता है। यह देर से आगमन अन्य सभी उत्तरों का खंडन करता है। अब मुझे नहीं पता कि क्या विश्वास करना चाहिए: ओ। (पुन: परीक्षण के दौरान मेरे स्वीकार किए गए उत्तर और निर्णय को
रोकें

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

5
@ जॉनी अधिकांश जावा एपीआई बुरी तरह से डिज़ाइन किया गया है। याद रखें कि इसका थोक दस साल से अधिक पुराना है और इस बीच कई सर्वोत्तम प्रथाओं का विकास किया गया है। लेकिन इसके लिए मेरा शब्द न लें: जावा इंजीनियर खुद ऐसा कहते हैं, सबसे पहले और जोश बलोच ने इस बारे में विस्तार से लिखा है, जैसे कि प्रभावी जावा में । आराम का आश्वासन दिया कि अगर जावा एपीआई आज विकसित किया गया था, तो यह बहुत अलग दिखाई देगा, और finalबहुत बड़ी भूमिका निभाएगा।
कोनराड रुडोल्फ

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

8

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


17
यह पूरी तरह से झूठ है! "भाषा के कीवर्ड का उपयोग केवल आपको कुछ संकेत देने के लिए [...] एक बुरा विचार है।" - इसके विपरीत, यह वही है जिसके लिए भाषा कीवर्ड हैं। आपका अस्थायी चेतावनी, "और केवल आप कभी भी इसका मतलब जानते हैं", निश्चित रूप से सही है, लेकिन यहां लागू नहीं होता है; finalउम्मीद के मुताबिक ओपी इस्तेमाल कर रहा है। इसमें कुछ भी गलत नहीं है। और एक बाधा को लागू करने के लिए एक भाषा सुविधा का उपयोग करना हमेशा एक टिप्पणी का उपयोग करने के लिए बेहतर होता है
कोनराड रुडोल्फ

8
@Konrad: सिवाय इसके finalकि "इस वर्ग का कोई उपवर्ग कभी नहीं बनाया जाना चाहिए" को निरूपित करना चाहिए (कानूनी कारणों या कुछ के लिए), न कि "इस वर्ग के वर्तमान में कोई बच्चे नहीं हैं, इसलिए मैं अभी भी इसके संरक्षित सदस्यों के साथ खिलवाड़ करने के लिए सुरक्षित हूं"। का इरादा final"स्वतंत्र रूप से संपादन योग्य" का बहुत विरोध है, और एक finalवर्ग के पास कोई protectedसदस्य भी नहीं होना चाहिए !
एसएफ।

3
@ कोनराड रूडोल्फ यह बिल्कुल भी मामूली नहीं है। यदि अन्य लोग बाद में अपनी कक्षाएं बढ़ाना चाहते हैं, तो एक टिप्पणी के बीच एक बड़ा अंतर है जो "विस्तारित नहीं" और एक कीवर्ड जो कहता है कि "विस्तार नहीं हो सकता है"।
जेरेमी

2
@ कोनराड रूडोल्फ जो ओओपी भाषा डिजाइन के बारे में एक प्रश्न लाने के लिए एक महान राय की तरह लगता है। लेकिन हम जानते हैं कि PHP कैसे काम करता है, और यह एक्सटेंशन की अनुमति के दूसरे दृष्टिकोण को लेता है जब तक कि सील न हो। यह कहते हुए कि खोजशब्दों को भ्रमित करने के लिए इसका ठीक है क्योंकि "यह कैसे होना चाहिए" यह केवल रक्षात्मकता है।
जेरेमी

3
@ जेरेमी मैं खोजशब्दों को भ्रमित नहीं कर रहा हूँ। कीवर्ड का finalअर्थ है, "इस वर्ग को अब [के लिए] बढ़ाया नहीं जाना है।" अधिक कुछ नहीं, कुछ भी कम नहीं। चाहे पीएचपी इसे ध्यान में दर्शन के साथ डिजाइन किया गया था अप्रासंगिक है: यह हैfinal कीवर्ड, सब के बाद। दूसरे, PHP के डिज़ाइन से बहस करना विफल है, यह देखते हुए कि कैसे पैचवर्क और बस समग्र रूप से PHP डिज़ाइन किया गया है।
कोनराड रुडोल्फ

5

"क्लास फाइनल घोषित करने के लिए" के बारे में एक अच्छा लेख है । इसके कुछ उद्धरण:

टीएल; डीआर: अपनी कक्षाओं को हमेशा बनाएं final, अगर वे एक इंटरफ़ेस लागू करते हैं, और कोई अन्य सार्वजनिक तरीके परिभाषित नहीं हैं

मुझे क्यों उपयोग करना है final?

  1. कयामत की व्यापक विरासत श्रृंखला को रोकना
  2. रचना को प्रोत्साहित करना
  3. उपयोगकर्ता सार्वजनिक API के बारे में सोचने के लिए डेवलपर को बाध्य करें
  4. किसी ऑब्जेक्ट के सार्वजनिक API को छोटा करने के लिए डेवलपर को बाध्य करें
  5. एक finalवर्ग हमेशा एक्स्टेंसिबल बनाया जा सकता है
  6. extends टूट जाता है
  7. आपको उस लचीलेपन की आवश्यकता नहीं है
  8. आप कोड बदलने के लिए स्वतंत्र हैं

कब बचें final :

अंतिम वर्ग केवल निम्नलिखित मान्यताओं के तहत प्रभावी ढंग से काम करते हैं:

  1. एक अमूर्त (इंटरफ़ेस) है जो अंतिम वर्ग को लागू करता है
  2. अंतिम वर्ग के सभी सार्वजनिक एपीआई उस इंटरफ़ेस का हिस्सा हैं

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

PS महान पढ़ने के लिए @ocramius को धन्यवाद!


5

एक वर्ग के लिए "अंतिम" का अर्थ है: आप एक उपवर्ग चाहते हैं? आगे बढ़ो, "अंतिम" को हटाएं, जितना चाहें उतना उप-वर्ग हटाएं, लेकिन अगर यह काम नहीं करता है तो मुझसे शिकायत न करें। आप अपने दम पर कर रहे हैं।

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


-1

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

जब तक आप वास्तव में नहीं हैं, तब तक चीजों को अंतिम रूप से चिह्नित न करें, वास्तव में इसका मतलब है।


धन्यवाद। क्या आप आगे बता सकते हैं। क्या आपका मतलब यह है कि अगर मैं एक वर्ग को final(परिवर्तन) के रूप में चिह्नित करता हूं तो मुझे इसे फिर से परीक्षण करना होगा?
JW01

4
मैं इसे और मजबूती से कहूंगा। जब तक क्लास के डिज़ाइन के कारण काम करने के लिए एक्सटेंशन नहीं किया जा सकता तब तक चीजों को अंतिम रूप में चिह्नित न करें।
सल।

धन्यवाद S.Lott - मैं यह समझने की कोशिश कर रहा हूं कि फाइनल का बुरा उपयोग कोड / प्रोजेक्ट को कैसे प्रभावित करता है। क्या आपने किसी बुरी डरावनी कहानियों का अनुभव किया है, जिसके चलते आप इसके इस्तेमाल के बारे में इतने हठधर्मी हो गए हैं final। क्या यह पहला हाथ अनुभव है?
JW01

1
@ JW01: एक finalवर्ग में एक प्राथमिक उपयोग का मामला है। आपके पास बहुरूपिए वर्ग हैं जिन्हें आप विस्तारित नहीं करना चाहते हैं क्योंकि एक उपवर्ग बहुरूपता को तोड़ सकता है। finalतब तक उपयोग न करें जब तक आपको उपवर्गों के निर्माण को रोकना नहीं चाहिए । इसके अलावा, यह बेकार है।
सल।

@ JW01, एक उत्पादन सेटिंग में आपको अंतिम रूप से हटाने की अनुमति नहीं दी जा सकती है , क्योंकि यह वह कोड नहीं है जिसे ग्राहक ने परीक्षण किया और अनुमोदित किया है। हालाँकि, आपको अतिरिक्त कोड (परीक्षण के लिए) जोड़ने की अनुमति दी जा सकती है, लेकिन आप वह नहीं कर सकते जो आप करना चाहते हैं क्योंकि आप अपनी कक्षा का विस्तार नहीं कर सकते।

-1

'फाइनल' का उपयोग करने से दूसरों की स्वतंत्रता छीन ली जाती है जो आपके कोड का उपयोग करना चाहते हैं।

यदि आपके द्वारा लिखा गया कोड केवल आपके लिए है और कभी भी जनता या ग्राहक को जारी नहीं किया जाएगा, तो आप अपने कोड के साथ वही कर सकते हैं, जो आप चाहते हैं। अन्यथा, आप दूसरों को अपने कोड पर निर्माण करने से रोकते हैं। बहुत बार मुझे एक एपीआई के साथ काम करना पड़ता है जो मेरी जरूरतों को पूरा करने में आसान होता, लेकिन तब मुझे 'फाइनल' में बाधा होती थी।

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

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

हालाँकि, यदि कार्यान्वयन बंद स्रोत है, तो आप अनुकूलन / विस्तार की संभावनाओं के बारे में कम प्रतिबंधों के साथ दूसरे API पर स्विच करने के साथ, वर्कअराउंड ढूंढने या सबसे खराब स्थिति में पीछे रह जाते हैं।

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


2
"इनहेरिटेंस कोड का पुन: उपयोग नहीं है"।
क्वांट_देव

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

@quant_dev: OOP में पुन: प्रयोज्य का अर्थ है सबसे पहले बहुरूपता। और वंशानुक्रम बहुरूपी व्यवहार (इंटरफ़ेस साझा करना) के लिए एक महत्वपूर्ण बिंदु है।
फाल्कन

@ फाल्कन शेयरिंग इंटरफ़ेस! = साझाकरण कोड। कम से कम सामान्य अर्थों में तो नहीं।
मात्रा_देव

3
@quant_dev: आपको ओओपी अर्थ में पुनरावृत्ति गलत लगती है। इसका मतलब है कि एक एकल विधि कई डेटाटिप्स पर काम कर सकती है, इंटरफ़ेस साझाकरण के लिए धन्यवाद। यह OOP कोड के पुन: उपयोग का एक प्रमुख हिस्सा है। और इनहेरिटेंस स्वचालित रूप से हम इंटरफेस को साझा करते हैं, इस प्रकार कोड रीससबिलिटी को काफी बढ़ाते हैं। इसलिए हम OOP में पुन: प्रयोज्यता की बात करते हैं। रूटीन के साथ लाइब्रेरी बनाना लगभग उतना ही पुराना है, जितना कि प्रोग्रामिंग करना और लगभग हर भाषा के साथ किया जा सकता है, यह आम है। OOP में कोड-पुन: उपयोग इससे कहीं अधिक है।
फाल्कन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.