CodeGym /Java Blog /अनियमित /विरोधी पैटर्न क्या हैं? आइए कुछ उदाहरण देखें (भाग 2)
John Squirrels
स्तर 41
San Francisco

विरोधी पैटर्न क्या हैं? आइए कुछ उदाहरण देखें (भाग 2)

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

8. सुनहरा हथौड़ा

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

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

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

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

9. समयपूर्व अनुकूलन

समयपूर्व अनुकूलन एक विरोधी पैटर्न है जिसका नाम खुद के लिए बोलता है।
"प्रोग्रामर कोड में गैर-महत्वपूर्ण स्थानों के बारे में सोचने और चिंता करने में बहुत समय व्यतीत करते हैं और उन्हें अनुकूलित करने का प्रयास करते हैं, जो केवल बाद के डिबगिंग और समर्थन को नकारात्मक रूप से प्रभावित करता है। हमें आम तौर पर 97% मामलों में अनुकूलन के बारे में भूलना चाहिए। इसके अलावा। , समयपूर्व अनुकूलन सभी बुराइयों की जड़ है। उस ने कहा, हमें शेष 3% पर ध्यान देना चाहिए।" — डोनाल्ड नुथ
उदाहरण के लिए, समय से पहले डेटाबेस में इंडेक्स जोड़ना। वह बुरा क्यों है? खैर, इसमें बुरा है, इंडेक्स को बाइनरी ट्री के रूप में संग्रहित किया जाता है। नतीजतन, हर बार एक नया मूल्य जोड़ा और हटा दिया जाता है, पेड़ की पुनर्गणना की जाएगी, और यह संसाधनों और समय का उपभोग करता है। इसलिए, अनुक्रमणिका को केवल तभी जोड़ा जाना चाहिए जब तत्काल आवश्यकता हो (यदि आपके पास बड़ी मात्रा में डेटा है और प्रश्न बहुत अधिक समय लेते हैं) और केवल सबसे महत्वपूर्ण फ़ील्ड के लिए (फ़ील्ड जो सबसे अधिक बार पूछे जाते हैं)।

10. स्पेगेटी कोड

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

public boolean someDifficultMethod(List<String> XMLAttrList) {
           ...
   int prefix = stringPool.getPrefixForQName(elementType);
   int elementURI;
   try {
       if (prefix == -1) {
        ...
           if (elementURI != -1) {
               stringPool.setURIForQName(...);
           }
       } else {
        ...
           if (elementURI == -1) {
           ...
           }
       }
   } catch (Exception e) {
       return false;
   }
   if (attrIndex != -1) {
       int index = attrList.getFirstAttr(attrIndex);
       while (index != -1) {
           int attName = attrList.getAttrName(index);
           if (!stringPool.equalNames(...)){
           ...
               if (attPrefix != namespacesPrefix) {
                   if (attPrefix == -1) {
                    ...
                   } else {
                       if (uri == -1) {
                       ...
                       }
                       stringPool.setURIForQName(attName, uri);
                   ...
                   }
                   if (elementDepth >= 0) {
                   ...
                   }
                   elementDepth++;
                   if (elementDepth == fElementTypeStack.length) {
                   ...
                   }
               ...
                   return contentSpecType == fCHILDRENSymbol;
               }
           }
       }
   }
}
यह भयानक लग रहा है, है ना? दुर्भाग्य से, यह सबसे आम एंटी-पैटर्न है :( यहां तक ​​कि ऐसा कोड लिखने वाला व्यक्ति भी भविष्य में इसे समझ नहीं पाएगा। कोड देखने वाले अन्य डेवलपर्स सोचेंगे, "ठीक है, अगर यह काम करता है, तो ठीक है — इसे न छूना बेहतर है"। अक्सर, एक विधि शुरू में सरल और बहुत पारदर्शी होती है, लेकिन जैसे-जैसे नई आवश्यकताएं जुड़ती जाती हैं, विधि धीरे-धीरे अधिक से अधिक सशर्त बयानों से घिर जाती है, इसे इस तरह एक राक्षसी में बदल देती है। यदि ऐसी विधि प्रतीत होता है, आपको इसे या तो पूरी तरह से या कम से कम सबसे भ्रमित करने वाले हिस्सों को रिफैक्टर करने की आवश्यकता है। आमतौर पर, किसी प्रोजेक्ट को शेड्यूल करते समय, रीफैक्टरिंग के लिए समय आवंटित किया जाता है, उदाहरण के लिए, स्प्रिंट समय का 30% रीफैक्टरिंग और परीक्षण के लिए होता है। बेशक, यह मानता है कोई हड़बड़ी नहीं है (लेकिन ऐसा कब होता है)।यहाँ

11. मैजिक नंबर

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

12. कॉपी-एंड-पेस्ट प्रोग्रामिंग

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

public static int max(int[] array) {
   int max = 0;
   for(int i = 0; i < array.length; i++) {
       if (Math.abs(array[i]) > max){
           max = array[i];
       }
   }
   return max;
}
हमें संख्या 3, 6, 1, 4, और 2 के साथ एक सरणी मिलती है, और विधि 6 लौटाती है। बढ़िया, इसे जारी रखें! लेकिन बाद में हमें 2.5, -7, 2 और 3 से मिलकर एक सरणी मिलती है, और फिर हमारा परिणाम -7 होता है। और यह परिणाम अच्छा नहीं है। यहाँ समस्या यह है कि Math.abs() निरपेक्ष मान लौटाता है। इसकी अज्ञानता आपदा की ओर ले जाती है, लेकिन केवल कुछ स्थितियों में। समाधान की गहन समझ के बिना, ऐसे कई मामले हैं जिन्हें आप सत्यापित नहीं कर पाएंगे। कॉपी किया गया कोड, शैलीगत रूप से और अधिक मौलिक, वास्तुशिल्प स्तर पर, एप्लिकेशन की आंतरिक संरचना से परे भी हो सकता है। ऐसे कोड को पढ़ना और बनाए रखना अधिक कठिन होगा। और निश्चित रूप से, हमें यह नहीं भूलना चाहिए कि सीधे किसी और के कोड की नकल करना एक विशेष प्रकार की साहित्यिक चोरी है।

13. पहिए का पुन: आविष्कार करना

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

14. यो-यो समस्या

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

public interface Technology {
   void turnOn();
}
परिवहन इंटरफ़ेस इसे इनहेरिट करता है:

public interface Transport extends Technology {
   boolean fillUp();
}
और फिर हमारे पास एक और इंटरफ़ेस है, ग्राउंडट्रांसपोर्ट:

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
और वहां से, हम एक सार कार वर्ग प्राप्त करते हैं:

public abstract class Car implements GroundTransportation {
   @Override
   public boolean fillUp() {
       /* some implementation */
       return true;
   }
   @Override
   public void turnOn() {
       /* some implementation */
   }
   public boolean openTheDoor() {
       /* some implementation */
       return true;
   }
   public abstract void fixCar();
}
अगला सार वोक्सवैगन वर्ग है:

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
और अंत में, एक विशिष्ट मॉडल:

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
यह शृंखला हमें इस तरह के सवालों के जवाब खोजने के लिए मजबूर करती है:
  1. कितने तरीके हैं VolkswagenAmarok?

  2. अधिकतम अमूर्तता प्राप्त करने के लिए प्रश्न चिह्न के बजाय किस प्रकार डाला जाना चाहिए:

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
इस तरह के सवालों का तुरंत जवाब देना मुश्किल है - इसके लिए हमें एक नज़र डालने और जांच करने की आवश्यकता होती है, और भ्रमित होना आसान होता है। और क्या होगा यदि पदानुक्रम सभी प्रकार के अधिभार और ओवरराइड के साथ बहुत बड़ा, लंबा और अधिक जटिल हो? अत्यधिक विखंडन के कारण हमारी संरचना अस्पष्ट होगी। सबसे अच्छा समाधान अनावश्यक विभाजनों को कम करना होगा। हमारे मामले में, हम प्रौद्योगिकी → कार → वोक्सवैगन अमारोक को छोड़ देंगे।

15. आकस्मिक जटिलता

अनावश्यक जटिलता एक विरोधी पैटर्न है जिसमें एक समाधान के लिए अनावश्यक जटिलताओं को पेश किया जाता है।
"कोई भी मूर्ख कोड लिख सकता है जिसे एक कंप्यूटर समझ सकता है। अच्छे प्रोग्रामर कोड लिखते हैं जिसे मनुष्य समझ सकते हैं।" — मार्टिन फाउलर
तो जटिलता क्या है? इसे कठिनाई की डिग्री के रूप में परिभाषित किया जा सकता है जिसके साथ कार्यक्रम में प्रत्येक ऑपरेशन किया जाता है। एक नियम के रूप में, जटिलता को दो प्रकारों में विभाजित किया जा सकता है। पहली तरह की जटिलता एक प्रणाली के कार्यों की संख्या है। इसे केवल एक ही तरीके से कम किया जा सकता है - कुछ फ़ंक्शन को हटाकर। मौजूदा तरीकों पर नजर रखने की जरूरत है। एक विधि को हटा दिया जाना चाहिए यदि यह अब उपयोग नहीं किया जाता है या अभी भी उपयोग किया जाता है लेकिन बिना कोई मूल्य लाए। क्या अधिक है, आपको यह आकलन करने की आवश्यकता है कि आवेदन में सभी विधियों का उपयोग कैसे किया जाता है, यह समझने के लिए कि निवेश कहाँ सार्थक होगा (बहुत सारे कोड पुन: उपयोग) और आप क्या नहीं कह सकते हैं। दूसरी प्रकार की जटिलता अनावश्यक जटिलता है। इसे केवल पेशेवर तरीके से ही ठीक किया जा सकता है। कुछ "अच्छा" करने के बजाय (युवा डेवलपर्स केवल इस बीमारी के लिए अतिसंवेदनशील नहीं हैं), आपको यह सोचने की ज़रूरत है कि इसे यथासंभव सरलता से कैसे किया जाए, क्योंकि सबसे अच्छा समाधान हमेशा सरल होता है। उदाहरण के लिए, मान लें कि हमारे पास कुछ संस्थाओं के विवरण के साथ छोटी संबंधित तालिकाएँ हैं, जैसे कि एक उपयोगकर्ता: विरोधी पैटर्न क्या हैं?  आइए कुछ उदाहरण देखें (भाग 2) - 3तो, हमारे पास उपयोगकर्ता की आईडी है, उस भाषा की आईडी जिसमें विवरण बनाया गया है, और विवरण ही है। इसी तरह, हमारे पास कारों, फाइलों, योजनाओं और ग्राहकों की तालिकाओं के लिए सहायक विवरणक हैं। फिर ऐसी तालिकाओं में नए मान सम्मिलित करना कैसा लगेगा?

public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
   switch (type){
       case CAR:
           jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
       case USER:
           jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
       case FILE:
           jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
       case PLAN:
           jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
       case CUSTOMER:
           jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
       default:
           throw new Exception();
   }
}
और तदनुसार, हमारे पास यह एनम है:

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
सब कुछ सरल और अच्छा लगता है... लेकिन अन्य तरीकों के बारे में क्या? दरअसल, उन सभी के पास switchस्टेटमेंट्स का एक गुच्छा और लगभग समान डेटाबेस क्वेरीज़ का एक गुच्छा होगा, जो बदले में हमारी कक्षा को बहुत जटिल और ब्लोट करेगा। यह सब कैसे आसान बनाया जा सकता है? आइए अपने एनम को थोड़ा अपग्रेड करें:

@Getter
@AllArgsConstructor
public enum ServiceType {
   CAR("cars_descriptions", "car_id"),
   USER("users_descriptions", "user_id"),
   FILE("files_descriptions", "file_id"),
   PLAN("plans_descriptions", "plan_id"),
   CUSTOMER("customers_descriptions", "customer_id");
   private String tableName;
   private String columnName;
}
अब प्रत्येक प्रकार की तालिका के मूल क्षेत्रों के नाम हैं। नतीजतन, विवरण बनाने की विधि बन जाती है:

private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
   jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
   }
सुविधाजनक, सरल और कॉम्पैक्ट, क्या आपको नहीं लगता? एक अच्छे डेवलपर का संकेत यह नहीं है कि वह कितनी बार पैटर्न का उपयोग करता है, बल्कि वह कितनी बार एंटी-पैटर्न से बचता है। अज्ञान सबसे बड़ा शत्रु है, क्योंकि आपको अपने शत्रुओं को दृष्टि से जानने की आवश्यकता है। खैर, मेरे पास आज के लिए बस इतना ही है। आप सभी को धन्यवाद! :)
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION