वह if स्टेटमेंट्स का विशाल गड़बड़ आपको घूरता रहता है। आपको लगता है कि आप कर सकते हैं इसे सरल बनाने में सक्षम, सिवाय उस बिजनेस लॉजिक के जो रास्ते में आती रहती है।
उदाहरण के लिए, मान लीजिए आपके पास एक सेल्स प्लेटफॉर्म है जहां आप Quote बनाते हैं, जिनमें कई LineItem होते हैं। सिवाय, आपके पास एक कोट में डुप्लीकेट लाइन आइटम हो सकते हैं अगर वे विज्ञापन हैं, लेकिन अगर आपके पास कई वेबसाइट्स हैं, तो आपको कीमतों को एक साथ जोड़ना होगा और इसे एक लाइन आइटम के रूप में दिखाना होगा। ओह और भी, अगर आप एक वेबसाइट खरीदते हैं और आपके कोट में पहले से पांच विज्ञापन हैं, तो आपको वेबसाइट पर 20% छूट देनी होगी।
मैं यहां से आपका लैपटॉप खिड़की से बाहर फेंकते हुए सुन सकता हूं।
आप हो सकता है इन नियमों को संभालने के लिए if स्टेटमेंट्स का एक गुच्छा लिखें:
class Quote attr_accessor :line_items ... def add_line_item(line_item) if line_item.kind_of?(Ad) self.line_items << line_item elsif line_item.kind_of?(Website) if @line_items.select {|item| item.kind_of?(Ad) }.length >= 5 # TODO: Put the fractions of a cent into a bank account # I have set up line_item.price *= 0.8 end existing_website = self.line_items.detect { |item| item.kind_of?(Website) } if existing_website existing_website.price += line_item.price else self.line_items << line_item end end end end लेकिन मुझे लगता है कि हम सहमत हो सकते हैं कि यह सिर्फ भयानक है। आप ऐसी किसी चीज को कैसे सुलझा सकते हैं?
आप मेथड को कई छोटे मेथड में विघटित कर सकते हैं, लेकिन यह आपके सभी खिलौनों को अपनी अलमारी में ठूंसने जैसा है ताकि आपकी माँ को लगे कि आपने अपना कमरा साफ कर लिया है। और वे kind_of?s अभी भी मुझे बहुत परेशान करेंगे।
लेकिन क्या होगा अगर आपने चीजों को लाइन आइटम के दृष्टिकोण से देखना शुरू कर दिया, कोट के बजाय? अगर पूछने के बजाय कि आप किस तरह के लाइन आइटम से निपट रहे हैं और इसे कोट में जोड़ रहे हैं, तो आपने बस बताया लाइन आइटम को खुद को कोट में जोड़ने के लिए?
अपने मेथड उल्टा करें!
कोड रिफैक्टर करने के मेरे पसंदीदा तरीकों में से एक है कॉलर और कली को उल्टा करने की कोशिश करना। यहां एक उदाहरण है, ऊपर दिए गए कोड का उपयोग करके:
class Quote ... def add_line_item(line_item) line_item.add_to_quote(self) end end class Ad < LineItem ... def add_to_quote(quote) quote.line_items << self end end class Website < LineItem def add_to_quote(quote) if quote.line_items.select {|item| item.kind_of?(Ad) }.length >= 5 # TODO: Put the fractions of a cent into a bank account # I have set up self.price *= 0.8 end existing_website = quote.line_items.detect { |item| item.kind_of?(Website) } if existing_website existing_website.price += self.price else quote.line_items << self end end end यह सही नहीं है। website.rb को अभी भी बहुत सारे रिफैक्टरिंग मदद की ज़रूरत है, और मैं इससे खुश नहीं हूं कि मेथड को उल्टा करने से line_items का एनकैप्सुलेशन कैसे टूट गया।
लेकिन आपने जटिलता की पहली परत को हटा दिया है। अब आप कोड को LineItem या Quote पर रख सकते हैं, यह इस पर निर्भर करता है कि यह सबसे अधिक समझ में कहां आता है। LineItem ऑब्जेक्ट प्रत्येक LineItem सबक्लास के बीच समानता और अंतर को संभालने के लिए विरासत और मिक्सिन का उपयोग कर सकते हैं। साथ ही, अपने add_line_item मेथड को फुलाए बिना नए LineItem सबक्लास जोड़ना अब वास्तव में आसान है।
आपका कोड थोड़ा क्लीनर है, और बहुत अधिक लचीला। तो आम तौर पर, मैं इसे एक जीत कहूंगा।
जहां आप इस पैटर्न का उपयोग नहीं करना चाहेंगे
जितना उपयोगी मेथड उल्टा करना है, कुछ कारण हैं जिनकी वजह से आप इस पैटर्न का उपयोग नहीं करना चाहेंगे:
-
यह एनकैप्सुलेशन तोड़ सकता है। आपको
Quoteऑब्जेक्ट पर उन विशेषताओं को उजागर करना पड़ सकता है जिन्हें आप सार्वजनिक रूप से उजागर नहीं करना चाहते थे। -
यह कपलिंग बढ़ा सकता है। अब
QuoteऔरAdदोनों को एक-दूसरे के बारे में जानने की आवश्यकता है। और इस पर निर्भर करता है कि उन्हें एक-दूसरे के बारे में कितना जानने की आवश्यकता है, यह आपके कोड को अधिक जटिल बना सकता है। -
यह
Adपर सिंगल रिस्पॉन्सिबिलिटी सिद्धांत का उल्लंघन कर सकता है, क्योंकि अबAdके पास यह जानने की जिम्मेदारी है कि खुद कोQuoteमें कैसे जोड़ा जाए।
आप आमतौर पर इन समस्याओं के आसपास काम कर सकते हैं। लेकिन आपको उनके बारे में पता होना चाहिए, क्योंकि आप नहीं चाहते कि रिफैक्टरिंग आपके कोड को खराब कर दे!
यह मेरे पसंदीदा में से एक क्यों है
उन समस्याओं के साथ भी, यह मेरा पसंदीदा रिफैक्टरिंग में से एक है। इस पैटर्न का उपयोग करने के बाद मैं जो कोड लिखता हूं वह स्पष्ट और अधिक आत्मविश्वास वाला होता है।
लेकिन तब भी जब ऐसा नहीं होता, इस पैटर्न का उपयोग करने से मुझे अपने ऑब्जेक्ट्स के बीच संबंधों के बारे में एक अलग तरीके से सोचने पर मजबूर होना पड़ता है। जब मैं "यह फीचर भयानक है, मुझे विश्वास नहीं हो रहा कि मुझे इसे संभालने के लिए यह भयानक कोड लिखना पड़ रहा है" वाली मानसिकता में फंस जाता हूं, तो यह मेरे दिमाग को उन समस्याओं को हल करने के नए तरीके देखने में लगा देता है। यह मुझे इस बारे में सोचने पर मजबूर करता है कि मैं अपने कोड को अलग तरीके से कैसे संरचित कर सकता हूं, और यह अविश्वसनीय रूप से उपयोगी है।
इसे अपने कोड में आज़माएं
मेरे कई पसंदीदा पैटर्न की तरह, मैं पहली बार मेथड उल्टा करना स्मॉलटॉक बेस्ट प्रैक्टिस पैटर्न में आया था, और यह तब से एक मूल्यवान टूल रहा है।
अगली बार जब आपको समान ऑब्जेक्ट्स से निपटने में कठिनाई हो जिनका व्यवहार थोड़ा अलग है, तो इसे आज़माएं! अगर आप नया कोड बेहतर पसंद करते हैं, तो इसे रखें। भले ही आप न करें, हालांकि, यह आपके दिमाग को एक ऐसे रास्ते पर ले जाएगा जो आपको बेहतर कोड तक ले जाएगा।