मैंने किसी को इस पर चर्चा नहीं देखी है इसलिए मैं विचार के लिए और अधिक भोजन में फेंक दूंगा। संक्षिप्त उत्तर/सलाह स्थानीय चरों पर इंस्टेंस चर का उपयोग नहीं करती है क्योंकि आपको लगता है कि वे मूल्यों को वापस करना आसान हैं। यदि आप स्थानीय चर और आवृत्ति चर का उचित उपयोग नहीं करते हैं तो आप अपने कोड के साथ बहुत मेहनत कर रहे हैं। आप कुछ गंभीर बग उत्पन्न करेंगे जो ट्रैक करना वाकई मुश्किल हैं। यदि आप समझना चाहते हैं कि गंभीर बग्स से मेरा क्या मतलब है, और यह क्या हो सकता है।
आइए केवल उदाहरण चरों को आजमाएं और प्रयोग करें क्योंकि आप कार्यों को लिखने का सुझाव देते हैं। मैं एक बहुत ही सरल वर्ग पैदा हो जाएगी:
public class BadIdea {
public Enum Color { GREEN, RED, BLUE, PURPLE };
public Color[] map = new Colors[] {
Color.GREEN,
Color.GREEN,
Color.RED,
Color.BLUE,
Color.PURPLE,
Color.RED,
Color.PURPLE };
List<Integer> indexes = new ArrayList<Integer>();
public int counter = 0;
public int index = 0;
public void findColor(Color value) {
indexes.clear();
for(index = 0; index < map.length; index++) {
if(map[index] == value) {
indexes.add(index);
counter++;
}
}
}
public void findOppositeColors(Color value) {
indexes.clear();
for(index = 0; i < index < map.length; index++) {
if(map[index] != value) {
indexes.add(index);
counter++;
}
}
}
}
यह एक मूर्खतापूर्ण कार्यक्रम मैं जानता हूँ कि है, लेकिन हम अवधारणा है कि चीजों के लिए उदाहरण चर का उपयोग कर की तरह यह एक काफी बुरा विचार है वर्णन करने के लिए उपयोग कर सकते हैं। सबसे बड़ी बात यह है कि आप पाएंगे कि वे विधियां हमारे पास मौजूद सभी इंस्टेंस चर का उपयोग करती हैं। और यह हर बार इंडेक्स, काउंटर, और इंडेक्स को संशोधित करता है जब उन्हें बुलाया जाता है। पहली समस्या जो आपको मिलेगी वह यह है कि उन तरीकों को कॉल करने के बाद एक दूसरे के बाद पूर्व रनों के उत्तरों को संशोधित कर सकता है।
BadIdea idea = new BadIdea();
idea.findColor(Color.RED);
idea.findColor(Color.GREEN); // whoops we just lost the results from finding all Color.RED
के बाद से findColor उदाहरण चर का उपयोग करता लौटे मानों को ट्रैक करने में हम केवल एक समय में एक परिणाम लौट सकते हैं: उदाहरण के लिए, यदि आप निम्नलिखित कोड लिखा था। !? के लिए प्रयास करें और इससे पहले कि हम फिर से इसे कहते उन परिणामों के लिए एक संदर्भ बंद सहेजने दें: इस दूसरे उदाहरण में
BadIdea idea = new BadIdea();
idea.findColor(Color.RED);
List<Integer> redPositions = idea.indexes;
int redCount = idea.counter;
idea.findColor(Color.GREEN); // this causes red positions to be lost! (i.e. idea.indexes.clear()
List<Integer> greenPositions = idea.indexes;
int greenCount = idea.counter;
हम 3 लाइन पर लाल पदों को बचाया है, लेकिन एक ही बात हुआ क्यों हम उन्हें खो थी ?! क्योंकि विचार.इंडेक्स को आवंटित करने के बजाए साफ़ कर दिया गया था, इसलिए एक समय में केवल एक ही जवाब इस्तेमाल किया जा सकता है। इसे फिर से कॉल करने से पहले आपको उस परिणाम का उपयोग करके पूरी तरह समाप्त करना होगा। एक बार फिर आप एक विधि को कॉल करने के बाद परिणाम साफ़ कर दिए जाते हैं और आप सबकुछ खो देते हैं। इसे ठीक करने के लिए आपको प्रत्येक बार एक नया परिणाम आवंटित करना होगा ताकि लाल और हरे रंग के उत्तर अलग हों। तो चलिए चीजों की नई प्रतियां बनाने के लिए हमारे उत्तरों को क्लोन करें:
BadIdea idea = new BadIdea();
idea.findColor(Color.RED);
List<Integer> redPositions = idea.indexes.clone();
int redCount = idea.counter;
idea.findColor(Color.GREEN);
List<Integer> greenPositions = idea.indexes.clone();
int greenCount = idea.counter;
ठीक है आखिरकार हमारे पास दो अलग-अलग परिणाम हैं।लाल और हरे रंग के परिणाम अब अलग हैं। लेकिन, हमें इस बारे में बहुत कुछ पता था कि कार्यक्रम के काम से पहले BadIdea ने आंतरिक रूप से कैसे काम किया था? हमें हर बार रिटर्न क्लोन करना याद रखना होगा जब भी हम सुरक्षित रूप से यह सुनिश्चित कर लें कि हमारे नतीजों को गिरफ्तार नहीं किया गया है। कॉलर को इन विवरणों को याद रखने के लिए मजबूर क्यों किया जाता है? अगर हमें ऐसा करने की ज़रूरत नहीं है तो क्या यह आसान नहीं होगा?
यह भी ध्यान दें कि कॉलर को परिणामों को याद रखने के लिए स्थानीय चर का उपयोग करना है, जबकि आपने BadIdea के तरीकों में स्थानीय चर का उपयोग नहीं किया है, तो कॉलर को परिणामों को याद रखने के लिए उनका उपयोग करना होगा। तो आप वास्तव में क्या हासिल किया? आपने वास्तव में समस्या को कॉलर को और अधिक करने के लिए मजबूर कर दिया। और जिस कॉलर को आपने कॉलर पर धक्का दिया है वह पालन करने का एक आसान नियम नहीं है क्योंकि नियम के कुछ अपवाद हैं।
अब दो अलग-अलग तरीकों से ऐसा करने का प्रयास करें। ध्यान दें कि मैं "स्मार्ट" कैसे रहा हूं और मैंने "स्मृति को बचाने" के लिए वही इंस्टेंस चर का पुन: उपयोग किया और कोड कॉम्पैक्ट रखा। ;-)
BadIdea idea = new BadIdea();
idea.findColor(Color.RED);
List<Integer> redPositions = idea.indexes;
int redCount = idea.counter;
idea.findOppositeColors(Color.RED); // this causes red positions to be lost again!!
List<Integer> greenPositions = idea.indexes;
int greenCount = idea.counter;
वही बात हुई! अरे, लेकिन मैं इतना "स्मार्ट" और स्मृति की बचत कर रहा था और कोड कम संसाधनों का उपयोग करता है !!! यह आवृत्ति चर का उपयोग करने का असली जोखिम है जैसे कि कॉलिंग विधियां अब ऑर्डर निर्भर हैं। यदि मैं विधि कॉल के आदेश को बदलता हूं तो परिणाम अलग-अलग होते हैं, भले ही मैंने वास्तव में BadIdea की अंतर्निहित स्थिति को नहीं बदला है। मैंने मानचित्र की सामग्री को नहीं बदला है। विभिन्न तरीकों से विधियों को कॉल करते समय कार्यक्रम अलग-अलग परिणाम क्यों देता है?
idea.findColor(Color.RED)
idea.findOppositeColors(Color.RED)
अगर मैं उन दो तरीकों बदली तुलना में एक अलग परिणाम का उत्पादन:
idea.findOppositeColors(Color.RED)
idea.findColor(Color.RED)
त्रुटियों के इन प्रकार के वास्तव में विशेष रूप से नीचे ट्रैक करने के लिए जब उन पंक्तियों सही एक दूसरे के बगल में नहीं हैं मुश्किल है। आप उन दो लाइनों के बीच कहीं भी एक नई कॉल जोड़कर और जंगली रूप से अलग-अलग परिणाम प्राप्त करके अपने कार्यक्रम को पूरी तरह से तोड़ सकते हैं। निश्चित रूप से जब हम छोटी संख्या में लाइनों से निपट रहे हैं तो त्रुटियों को पहचानना आसान है। लेकिन, एक बड़े कार्यक्रम में आप उन्हें पुन: पेश करने की कोशिश कर रहे दिन बर्बाद कर सकते हैं भले ही कार्यक्रम में डेटा नहीं बदला गया हो।
और यह केवल एकल थ्रेडेड समस्याओं को देखता है। यदि BadIdea का उपयोग बहु-थ्रेडेड स्थिति में किया जा रहा था तो त्रुटियां वास्तव में विचित्र हो सकती हैं। क्या होता है यदि FindColors() और findOppositeColors() को एक ही समय में बुलाया जाता है? क्रैश, आपके सभी बाल गिर जाते हैं, मौत, अंतरिक्ष और समय एकवचन में पतन हो जाता है और ब्रह्मांड निगल जाता है? शायद उनमें से कम से कम दो। थ्रेड शायद आपके सिर से ऊपर हैं, लेकिन उम्मीद है कि हम आपको बुरी चीजें करने से दूर ले जा सकते हैं, इसलिए जब आप धागे को प्राप्त करते हैं तो उन बुरे प्रथाओं से आपको वास्तविक दिल का दर्द नहीं होता है।
क्या आपने देखा कि विधियों को कॉल करते समय आपको कितना सावधान रहना पड़ा था? उन्होंने एक-दूसरे को ओवरराइट किया, उन्होंने स्मृति को संभवतः यादृच्छिक रूप से साझा किया, आपको यह याद रखना था कि यह बाहरी पर काम करने के लिए अंदर कैसे काम करता है, जिस क्रम में चीजों को बुलाया जाता है, अगली पंक्तियों में बहुत बड़े बदलाव होते हैं, और यह केवल एक धागे की स्थिति में ही काम कर सकता है। इस तरह की चीजें करने से वास्तव में भंगुर कोड उत्पन्न होता है जो जब भी आप इसे छूते हैं तो अलग हो जाते हैं। मैंने दिखाए गए इन अभ्यासों को सीधे भंगुर कोड में योगदान दिया।
हालांकि यह encapsulation की तरह लग सकता है यह सटीक विपरीत है क्योंकि आपने इसे कैसे लिखा है के तकनीकी विवरण को कॉलर पर जाना जाना है। कॉलर को अपना कोड उनके कोड को काम करने के लिए एक विशेष तरीके से लिखना है, और वे आपके कोड के तकनीकी विवरणों के बारे में जानने के बिना ऐसा नहीं कर सकते हैं। इसे अक्सर लीकी एब्स्ट्रक्शन कहा जाता है क्योंकि कक्षा को एक अमूर्त/इंटरफ़ेस के पीछे तकनीकी विवरण छिपाने का अनुमान है, लेकिन तकनीकी विवरण कॉलर को उनके व्यवहार को बदलने के लिए मजबूर कर देता है।प्रत्येक समाधान में कुछ हद तक लीकी-नेस होती है, लेकिन इन गारंटीओं की तरह उपरोक्त तकनीकों में से कोई भी इससे कोई फर्क नहीं पड़ता कि आप इसे हल करने की कोशिश कर रहे हैं, यदि आप उन्हें लागू करते हैं तो यह बहुत ही कमजोर होगा। तो आइए अब गुडइडा को देखें।
आइए स्थानीय चर का उपयोग कर रीराइट:
public class GoodIdea {
...
public List<Integer> findColor(Color value) {
List<Integer> results = new ArrayList<Integer>();
for(int i = 0; i < map.length; i++) {
if(map[index] == value) {
results.add(i);
}
}
return results;
}
public List<Integer> findOppositeColors(Color value) {
List<Integer> results = new ArrayList<Integer>();
for(int i = 0; i < map.length; i++) {
if(map[index] != value) {
results.add(i);
}
}
return results;
}
}
यह हर समस्या हम ऊपर चर्चा करता है। मुझे पता है कि मैं काउंटर का ट्रैक नहीं रख रहा हूं या इसे वापस नहीं कर रहा हूं, लेकिन अगर मैंने किया तो मैं एक नई कक्षा बना सकता हूं और सूची के बदले वापस कर सकता हूं। कभी कभी मैं एक से अधिक परिणाम जल्दी से वापस जाने के लिए निम्नलिखित वस्तु का उपयोग करें:
public class Pair<K,T> {
public K first;
public T second;
public Pair(K first, T second) {
this.first = first;
this.second = second;
}
}
लांग जवाब है, लेकिन एक बहुत महत्वपूर्ण विषय।
क्या आपको अन्य कक्षाओं को परिभाषित करने की अनुमति है? –