सुरक्षित चर से बचने के लिए क्लीन कोड का सुझाव क्यों है?


168

क्लीन कोड "फ़ॉर्मेटिंग" अध्याय के "वर्टिकल डिस्टेंस" खंड में संरक्षित चर से बचने का सुझाव देता है:

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

तर्क क्या है?


7
एक उदाहरण दिखाएं जहां आपको लगता है कि आपको इसकी आवश्यकता है
gnat

63
मैं उस पुस्तक में सुसमाचार के रूप में ज्यादा नहीं लेगा।
रिग

40
@ आप इन हिस्सों में ईश निंदा पर टिप्पणी कर रहे हैं
रायथल

40
आई 'म ओके विद दैट। मैंने किताब पढ़ ली है और इस पर मेरी अपनी राय हो सकती है।
रिग

10
मैंने किताब पढ़ ली है और हालाँकि मैं वहाँ के अधिकांश बातों से सहमत हूँ, मैं यह नहीं कहूँगा कि मैं इसे सुसमाचार मानता हूँ। मुझे लगता है कि हर स्थिति अलग है .. और किताब में प्रतिनिधित्व किए गए सटीक दिशानिर्देशों से चिपके रहना बहुत सारी परियोजनाओं के लिए काफी मुश्किल है।
साइमन व्हाइटहेड

जवाबों:


277

संरक्षित चर को टाला जाना चाहिए क्योंकि:

  1. वे YAGNI मुद्दों का नेतृत्व करते हैं। जब तक आपके पास एक वंशज वर्ग नहीं है जो वास्तव में संरक्षित सदस्य के साथ सामान करता है, इसे निजी बनाएं।
  2. वे एलएसपी मुद्दों का नेतृत्व करते हैं। संरक्षित चर में आम तौर पर उनके साथ जुड़े कुछ आंतरिक आक्रमण होते हैं (या फिर वे सार्वजनिक होंगे)। इनहेरिटर्स को फिर उन गुणों को बनाए रखने की आवश्यकता होती है, जिन्हें लोग खराब कर सकते हैं या जानबूझकर उल्लंघन कर सकते हैं।
  3. वे OCP का उल्लंघन करते हैं । यदि बेस क्लास संरक्षित सदस्य के बारे में बहुत अधिक धारणाएं बनाता है, या इनहेरिटर वर्ग के व्यवहार के साथ बहुत अधिक लचीला है, तो यह बेस क्लास के व्यवहार को उस विस्तार से संशोधित कर सकता है।
  4. वे रचना के बजाय विस्तार के लिए विरासत का नेतृत्व करते हैं। यह सख्त युग्मन, SRP के अधिक उल्लंघन , अधिक कठिन परीक्षण, और अन्य चीजों की एक निंदा करता है जो 'वंशानुक्रम पर चर्चा रचना' के भीतर आते हैं।

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


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

2
ऐसा लगता है कि अंकल बॉब ऊर्ध्वाधर दूरी का उल्लेख कर रहे हैं जब कोई कक्षाओं के बीच संरक्षित सदस्य का उल्लेख कर रहा है , और उसी कक्षा में नहीं।
रॉबर्ट हार्वे

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

2
@ steve314 मैं ऐसे परिदृश्य की कल्पना नहीं कर सकता जहाँ आधार वर्ग और उसके सभी उत्तराधिकारी केवल एक ही फ़ाइल में रहेंगे। एक उदाहरण के बिना मैं यह सोचने के लिए इच्छुक हूं कि यह विरासत या खराब अमूर्तता का दुरुपयोग है।
तेलस्टिन

3
YAGNI = आपको Aint की आवश्यकता है, इसके लिए LSP = Liskov प्रतिस्थापन सिद्धांत OCP = ओपन / क्लोज प्रिंसिपल SRP = सिंगल रिस्पांसिबिलिटी प्रिंसिपल
ब्रायन ग्लेजर

54

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


26

मैंने किताब नहीं पढ़ी है, लेकिन मैं अंकल बॉब के कहने पर एक छुरा ले सकता हूं।

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

समस्या को ठीक करने के लिए, आप चर को संरक्षित संपत्ति में संलग्न कर सकते हैं, जैसे:

protected string Name
{
    get { return name; }
    private set { name = value; }
}

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


आपने संरक्षित सेटर के साथ सार्वजनिक संपत्ति बनाई। संरक्षित क्षेत्र को निजी सेटर के साथ संरक्षित संपत्ति के साथ हल किया जाना चाहिए।
एंडी

2
अब +1। सेटर को भी संरक्षित किया जा सकता है, मुझे लगता है, लेकिन आधार आईडी को लागू कर सकता है यदि नया मान मान्य है या नहीं।
एंडी

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

2
वहाँ एक है विशाल के बीच का अंतर protectedऔर publicसदस्य हैं। यदि BaseTypeएक सार्वजनिक सदस्य को उजागर करता है, तो इसका मतलब है कि सभी व्युत्पन्न प्रकारों में वही सदस्य काम करने चाहिए, क्योंकि एक DerivedTypeउदाहरण कोड को पारित किया जा सकता है जो एक BaseTypeसंदर्भ प्राप्त करता है और उस सदस्य का उपयोग करने की अपेक्षा करता है । इसके विपरीत, अगर BaseTypeएक को उजागर करता protectedसदस्य है, तो DerivedTypeउस सदस्य का उपयोग करने की अपेक्षा कर सकते हैं base, लेकिन baseकुछ नहीं हो सकता अन्य एक से BaseType
सुपरटेक

18

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

संरक्षित सदस्य चर दो स्थानों पर बिखरे हुए हैं, और, थोड़े जादू की तरह दिखता है। आप इस चर का संदर्भ है, फिर भी इसे यहाँ से परिभाषित नहीं है ... जहां है यह परिभाषित? और इस तरह शिकार शुरू होता है। protectedपूरी तरह से बचने के लिए बेहतर है , उसका तर्क।

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


9

कुछ बहुत अच्छे जवाब यहाँ पहले से ही। लेकिन जोड़ने वाली बात:

अधिकांश आधुनिक OO भाषाओं में, यह एक अच्छी आदत है (Java AFAIK में इसकी आवश्यक) प्रत्येक वर्ग को अपनी फ़ाइल में डालने के लिए (कृपया C ++ के बारे में कुछ भी नहीं मिलता है, जहां आपके पास अक्सर दो फाइलें होती हैं)।

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


1
स्विफ्ट में नहीं। दिलचस्प बात यह है कि स्विफ्ट के पास "संरक्षित" नहीं है, लेकिन इसमें "फाइलपेयर" है, जो "संरक्षित" और सी ++ "दोस्त" दोनों को बदलता है।
gnasher729

@ gnasher729 - बेशक, स्विफ्ट की विरासत में बहुत सारे स्मालटॉक हैं। स्मालटाक के पास निजी चर और सार्वजनिक तरीकों के अलावा कुछ भी नहीं है। और स्मॉलटाकल में निजी का मतलब निजी है: एक ही वर्ग के दो ऑब्जेक्ट भी एक-दूसरे के चर तक नहीं पहुंच सकते हैं।
जूल्स

4

मूल विचार यह है कि एक "फ़ील्ड" (उदाहरण-स्तरीय चर) जिसे संरक्षित घोषित किया गया है, संभवतः यह अधिक दृश्यमान है जितना कि यह होना चाहिए, और इससे कम "संरक्षित" आप की तरह हो सकता है। C / C ++ / Java / C # में कोई एक्सेस मोडिफायर नहीं है, जो "एक ही असेंबली के भीतर केवल बाल कक्षाओं द्वारा सुलभ" के बराबर है, इस प्रकार आपको अपने स्वयं के बच्चों को परिभाषित करने की क्षमता प्रदान करता है जो आपके असेंबली में फ़ील्ड का उपयोग कर सकते हैं, लेकिन अन्य विधानसभाओं में बनाए गए बच्चों को समान पहुंच की अनुमति नहीं देना; C # में आंतरिक और संरक्षित संशोधक हैं, लेकिन उनका संयोजन "आंतरिक या संरक्षित" पहुंच बनाता है, न कि "आंतरिक और संरक्षित"। तो, एक ऐसा क्षेत्र जो संरक्षित है, किसी भी बच्चे द्वारा सुलभ है, चाहे आपने उस बच्चे को लिखा हो या किसी और ने। इस प्रकार संरक्षित एक हैकर के लिए एक खुला दरवाजा है।

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

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

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


4

यह एक दिलचस्प चर्चा है।

फ्रैंक होने के लिए, अच्छे उपकरण इन "ऊर्ध्वाधर" मुद्दों में से कई को कम कर सकते हैं। वास्तव में, मेरी राय में "फाइल" की धारणा वास्तव में कुछ है जो सॉफ्टवेयर विकास में बाधा डालती है - कुछ लाइट टेबल प्रोजेक्ट पर काम कर रही है (http://www.chris-granger.com/2012/04/12/light- तालिका --- एक-new-आईडीई अवधारणा /)।

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

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

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


0

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

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

हालाँकि, आपको यह सभी विज्ञापन लिटम नहीं लेना चाहिए, केवल एक गिल्डलाइन के रूप में; यदि संरक्षित चर बहुत खराब हैं, तो उन्हें पहले स्थान पर भाषा के अंदर नहीं रखा जाएगा। संरक्षित क्षेत्रों imho के लिए एक उचित स्थान एक परीक्षण ढांचे से बेस क्लास के अंदर है (एकीकरण परीक्षण कक्षाएं इसे बढ़ाती हैं)।


1
ऐसा मत मानिए क्योंकि कोई भाषा इसकी अनुमति देती है, ऐसा करना ठीक है। मुझे यकीन नहीं है कि वास्तव में संरक्षित क्षेत्रों की अनुमति देने के लिए एक ईश्वर कारण है; हम वास्तव में उन्हें मेरे नियोक्ता पर अस्वीकार कर देते हैं।
एंडी

2
@Andy आपने जो कहा, वह आपने नहीं पढ़ा है; मैंने कहा कि संरक्षित क्षेत्रों की सिफारिश नहीं की जाती है और इसके लिए कारण हैं। स्पष्ट रूप से ऐसे परिदृश्य हैं जिनमें संरक्षित चर की आवश्यकता होती है; आप केवल उपवर्गों में एक निरंतर अंतिम मान चाहते हैं।
m3th0dman

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

3
@ और यह बहुत स्पष्ट है कि जब से मैं संरक्षित चर का जिक्र कर रहा हूं मैं स्थानीय या पैरामीटर चर के बारे में नहीं बल्कि खेतों के बारे में बात कर रहा था। मैंने ऐसे परिदृश्य का भी उल्लेख किया है जहाँ गैर-स्थिर संरक्षित चर उपयोगी हैं; imho प्रोग्रामर्स कोड लिखने के तरीके को लागू करना किसी कंपनी के लिए गलत है।
m3th0dman

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

0

मुझे लगता है कि JUnit परीक्षणों के लिए संरक्षित चर का उपयोग करना उपयोगी हो सकता है। यदि आप उन्हें निजी बनाते हैं तो आप उन्हें प्रतिबिंब के बिना परीक्षण के दौरान एक्सेस नहीं कर सकते। यह उपयोगी हो सकता है यदि आप कई राज्य परिवर्तनों के माध्यम से एक जटिल प्रक्रिया का परीक्षण कर रहे हैं।

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


-1

हां, मैं मानता हूं कि यह कुछ अजीब बात है कि (जैसा कि मुझे याद है) किताब में सभी गैर-निजी चरों के बारे में भी चर्चा की गई है, जिससे कुछ बचा जा सके।

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

मुझे लगता है कि सब कुछ सार्वजनिक करने के लिए एक और दिलचस्प दृष्टिकोण है, जो आपको छोटे वर्गों के लिए मजबूर कर देगा, जो बदले में पूरे ऊर्ध्वाधर दूरी मीट्रिक को कुछ हद तक लूटता है।

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