रणनीति पैटर्न के लाभ


15

रणनीति पैटर्न का उपयोग करना क्यों फायदेमंद है यदि आप सिर्फ / फिर मामलों में अपना कोड लिख सकते हैं?

उदाहरण के लिए: मेरे पास एक करदाता वर्ग है, और इसके तरीकों में से एक अलग एल्गोरिदम का उपयोग कर करों की गणना करता है। तो ऐसा क्यों नहीं हो सकता है अगर / या मामलों और रणनीति पद्धति का उपयोग करने के बजाय उस विधि में उपयोग करने के लिए एल्गोरिथ्म का पता लगाएं? इसके अलावा, आप सिर्फ करदाता वर्ग में प्रत्येक एल्गोरिथ्म के लिए एक अलग विधि क्यों लागू नहीं कर सकते हैं?

इसके अलावा, एल्गोरिथ्म के रनटाइम में बदलने का क्या मतलब है?


2
क्या यह होमवर्क है? यह बताने के लिए बेहतर है कि यदि ऐसा है तो सामने वाले को।
फुहरमेनटर

2
@Fuhrmanator नहीं यह नहीं है
Armon

जवाबों:


20

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

तो, नेस्टेड के साथ if/elseआप अपने कोड के एक हिस्से के लिए कई परीक्षणों के साथ समाप्त करेंगे, जबकि रणनीति के साथ आपके पास कई सरलतम रणनीतियों में से प्रत्येक के लिए कुछ परीक्षण होंगे। उत्तरार्द्ध के साथ, बेहतर कवरेज करना आसान है, क्योंकि निष्पादन पथ को याद रखना कठिन है।

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

यहाँ रणनीति पैटर्न है:

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

आप इसके साथ ऐसा नहीं कर सकते if/else, क्योंकि इसके लिए रूपरेखा के कोड को बदलने की आवश्यकता होगी, जिस स्थिति में यह अब एक ढांचा नहीं होगा। चूंकि फ्रेमवर्क को अक्सर संकलित रूप में वितरित किया जाता है, इसलिए यह एकमात्र विकल्प हो सकता है।

फिर भी, भले ही आप कुछ नियमित कोड लिखें, लेकिन रणनीति फायदेमंद है क्योंकि यह आपके इरादों को स्पष्ट करता है। यह कहता है "यह तर्क प्लग करने योग्य और सशर्त है", यानी कई कार्यान्वयन हो सकते हैं जो उपयोगकर्ता के कार्यों, कॉन्फ़िगरेशन या यहां तक ​​कि प्लेटफॉर्म के आधार पर भिन्न हो सकते हैं।

रणनीति पैटर्न का उपयोग करने से पठनीयता में सुधार हो सकता है , क्योंकि एक वर्ग जो कुछ विशेष रणनीति को लागू करता है, आमतौर पर एक वर्णनात्मक नाम होना चाहिए, उदाहरण के लिए USAIncomeTaxCalculator, if/elseब्लॉक "नामहीन" हैं, सर्वोत्तम मामलों में केवल टिप्पणी की गई है, और टिप्पणियां झूठ हो सकती हैं। इसके अलावा, मेरे व्यक्तिगत स्वाद को फ्राई करें, बस if/elseएक पंक्ति में 3 ब्लॉक पढ़ने योग्य नहीं हैं, और यह नेस्टेड ब्लॉक के साथ बहुत खराब हो जाता है।

खुला / बंद सिद्धांत , यह भी बहुत प्रासंगिक है, क्योंकि जैसा कि मैंने ऊपर के उदाहरण में वर्णित, रणनीति आप उन भागों (पुनर्लेखन "संशोधन के लिए बंद किया गया" के बिना अपने कोड ( "विस्तार के लिए खुला") के कुछ हिस्सों में एक तर्क का विस्तार करने की अनुमति देता है )।


1
if/elseब्लॉक भी कोड पठनीयता को कम करते हैं। रणनीति पैटर्न के लिए, ओपन / क्लोज्ड सिद्धांत IMO का उल्लेख करने योग्य है।
मैकीज चलापक

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

जवाब के लिए धन्यवाद। तो क्यों कठबोली मैं एक ही कक्षा में विभिन्न एल्गोरिदम के लिए अलग-अलग तरीकों का उपयोग कर सकता हूं?
अरमान सफई

आप कर सकते हैं, लेकिन आपको अभी भी if/elseउन्हें (या उनके अंदर, यह निर्धारित करने के लिए कि यह कुछ करना चाहिए या नहीं) कॉल करने के लिए ब्लॉकों के एक समूह की आवश्यकता होगी , इसलिए यह शायद अधिक पढ़ने योग्य कोड को छोड़कर, बहुत मदद नहीं है। और फिर आपके काल्पनिक ढांचे के उपयोगकर्ताओं के लिए भी कोई एक्स्टेंसिबिलिटी नहीं है।
स्क्रिप्टिन

1
क्या आप इस बारे में स्पष्ट हो सकते हैं कि परीक्षण करना आसान क्यों है? एक पॉलीमॉर्फ़िक विधि (रणनीति के लिए आधार) के लिए एक केस स्टेटमेंट (या अगर / फिर) को फिर से भरने के लिए उदाहरण परीक्षण करना बहुत आसान है। refactoring.com/catalog/replaceConditionalWithPolymorphism.html यदि मुझे परीक्षण करने के लिए सभी शर्तें पता हैं, तो मैं प्रत्येक के लिए एक परीक्षण लिखता हूं। यदि मेरे पास रणनीति है, तो मुझे प्रत्येक के लिए एक को त्वरित और निष्पादित करना होगा। रणनीति दृष्टिकोण कैसे परीक्षण करना आसान है? जब आप रणनीति के लिए रिफ्लेक्टर करते हैं तो हम जटिल नेस्टेड के बारे में बात नहीं कर रहे हैं।
फुहरमैनटेर

5

रणनीति पैटर्न का उपयोग करना क्यों फायदेमंद है यदि आप सिर्फ / फिर मामलों में अपना कोड लिख सकते हैं?

कभी-कभी आपको सिर्फ / अगर उपयोग करना चाहिए। यह सरल कोड है जिसे पढ़ना आसान है।

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

दूसरी समस्या कपलिंग की है। यदि / तो का उपयोग करके, सभी कार्यान्वयन उस कार्यान्वयन से बंधे होते हैं, जिससे उन्हें भविष्य में बदलने के लिए कठिन हो जाता है। रणनीति का उपयोग करके, केवल युग्मन रणनीति के इंटरफेस के लिए है।


यदि / फिर कोड में कोड को संशोधित करने में क्या गलत है? यदि आप एल्गोरिदम के कार्यों में से एक को बदलने का निर्णय लेते हैं तो क्या आपको रणनीति पैटर्न में कोड को संशोधित करना होगा?
अरमान सफ़ाई

@armonsafai - यदि आप रणनीति को संशोधित करते हैं, तो आपको बस रणनीति का परीक्षण करने की आवश्यकता है। यदि आप सभी एल्गोरिदम को संशोधित करते हैं, तो आपको सभी एल्गोरिदम का परीक्षण करने की आवश्यकता है। इससे भी बदतर, यदि आप एक नई रणनीति जोड़ते हैं, तो आपको बस रणनीति का परीक्षण करने की आवश्यकता है। यदि आप एक नया सशर्त जोड़ते हैं, तो आपको सभी सशर्त परीक्षण करने की आवश्यकता है।
तेलेस्टिन

4

जब if/thenस्थितियां http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html में बताई गई हों, तो रणनीति उपयोगी होती है

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

रणनीति का मुख्य कारण GoF पुस्तक p.316 में बताया गया है जिसने पैटर्न पेश किया:

जब रणनीति पैटर्न का उपयोग करें

...

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

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

if/thenसशर्त के साथ , सशर्त तर्क वाले वर्ग के कोड को बदलना आवश्यक है। जैसा कि अन्य उत्तरों में उल्लेख किया गया है, कभी-कभी यह ठीक है जब आप पुन: संकलन के बिना नई कार्यक्षमता (प्लग-इन) को जोड़ने के लिए जटिलता को जोड़ना नहीं चाहते हैं।


3

[...] अगर आप सिर्फ / अगर मामलों में अपना कोड लिख सकते हैं?

यह रणनीतिक पैटर्न का सबसे बड़ा लाभ है। स्थितियां नहीं हैं।

आप चाहते हैं कि आपकी कक्षाएं / विधियाँ / कार्य यथासंभव सरल और संक्षिप्त हों। शॉर्ट कोड टेस्ट करना बहुत आसान है और पढ़ने में बहुत आसान है।

स्थितियां ( if/ elseif/ else) आपकी कक्षाएं / विधियाँ / कार्य लंबे करती हैं, क्योंकि आमतौर पर कोड जहां एक निर्णय का मूल्यांकन करता trueहै, वह उस हिस्से से अलग होता है जहां निर्णय का मूल्यांकन होता है false


रणनीति पैटर्न का एक और बड़ा लाभ यह है, यह आपकी पूरी परियोजना में पुन: प्रयोज्य है।

रणनीति डिजाइन पैटर्न का उपयोग करते समय, आपके पास कुछ प्रकार के IoC कंटेनर होने की संभावना है, जिससे आप एक इंटरफ़ेस का वांछित कार्यान्वयन प्राप्त कर रहे हैं, शायद एक getById(int id)विधि द्वारा , जहांid एक एन्यूमरेटर सदस्य हो सकता है।

इसका मतलब है, कार्यान्वयन का निर्माण आपके कोड के केवल एक स्थान पर है।

यदि आप अधिक कार्यान्वयन जोड़ना चाहते हैं, तो आप नए कार्यान्वयन को इसमें जोड़ते हैं getById विधि में और यह परिवर्तन उस कोड में हर जगह दिखाई देता है जहाँ आप इसे कहते हैं।

के साथ if/ elseif/ elseयह करना असंभव है। एक नया कार्यान्वयन जोड़कर, आपको एक नया elseifब्लॉक जोड़ना होगा और इसे हर जगह करना होगा जहाँ कार्यान्वयन का उपयोग किया गया था, या आप एक कोड के साथ समाप्त हो सकते हैं जो अमान्य है, क्योंकि आप इसके संरचना में कार्यान्वयन जोड़ना भूल गए।


इसके अलावा, एल्गोरिथ्म के रनटाइम में बदलने का क्या मतलब है?

मेरे उदाहरण में, idएक चर हो सकता है जो एक उपयोगकर्ता इनपुट के आधार पर आबादी है। यदि उपयोगकर्ता एक बटन ए पर क्लिक करता है, तो id = 2, यदि वह एक बटन बी पर क्लिक करता है, तो id = 8

अलग-अलग idमूल्य के कारण, आईओसी कंटेनर से एक इंटरफ़ेस का एक अलग कार्यान्वयन प्राप्त होता है और कोड अलग-अलग संचालन करता है।


जवाब के लिए धन्यवाद। तो क्यों कठबोली मैं एक ही कक्षा में विभिन्न एल्गोरिदम के लिए अलग-अलग तरीकों का उपयोग कर सकता हूं?
अरमान सफई

@ArmonSafai अलग तरीके वास्तव में कुछ भी हल करेगा? मुझे ऐसा नहीं लगता। आप समस्या को एक स्थान से दूसरे स्थान पर ले जा रहे हैं, और निर्णय करने के लिए कि किस विधि को कॉल करना है, एक शर्त के आधार पर किया जाएगा। फिर, एक if/ elseif/ elseराज्य। पहले की तरह ही, अलग जगह पर।
एंडी

तो अगर / फिर मामले मुख्य अधिकार में होंगे? यदि आपको रणनीति पैटर्न के लिए मुख्य रूप से मामलों का उपयोग करना है, तो आपको नहीं करना चाहिए?
अरमान सफई

1
@ArmonSafai नहीं, आप नहीं करेंगे। आपके पास विधि idमें चर पर एक स्विच getByIdहोगा, जो विशिष्ट कार्यान्वयन को वापस करेगा। हर बार जब आपको इंटरफ़ेस के कार्यान्वयन की आवश्यकता होगी, तो आप आईओसी कंटेनर को इसे आपको वितरित करने के लिए कहेंगे।
एंडी

1
@ArmonSafai आप getSortByEnumType(SortEnum type)एक Sortइंटरफ़ेस के कार्यान्वयन को वापस करने की एक विधि के रूप में अच्छी तरह से कर सकते हैं , getSortTypeएक SortEnumचर को वापस करने और एक पैरामीटर के रूप में एक संग्रह लेने की getSortByEnumTypeविधि है , और विधि फिर से typeपैरामीटर पर एक स्विच होता है जो आपको सही सॉर्टिंग एल्गोरिथ्म लौटाता है। यदि आपको एक नया सॉर्टिंग एल्गोरिदम जोड़ने की आवश्यकता है, तो आपको केवल एनम और एक विधि को संपादित करने की आवश्यकता है। और आप सेट हैं।
एंडी

2

रणनीति पैटर्न का उपयोग करना क्यों फायदेमंद है यदि आप सिर्फ / फिर मामलों में अपना कोड लिख सकते हैं?

रणनीति पैटर्न आपको अपने एल्गोरिदम (विवरण) को व्यवसाय तर्क (उच्च स्तरीय नीति) से अलग करने देता है। मिश्रित होने पर ये दोनों चीजें न केवल पढ़ने के लिए भ्रमित करती हैं, बल्कि बदलने के बहुत अलग कारण भी हैं।

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

इसके अलावा, एल्गोरिथ्म के रनटाइम में बदलने का क्या मतलब है?

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


1

if/elseप्रति सेर कुछ गलत नहीं है । कई मामलों if/elseमें तर्क व्यक्त करने का सबसे सरल और सबसे पठनीय तरीका है। इसलिए आपके द्वारा वर्णित दृष्टिकोण कई मामलों में पूरी तरह से मान्य है। (यह पूरी तरह से परीक्षण योग्य भी है, इसलिए यह कोई मुद्दा नहीं है।)

लेकिन कुछ विशेष मामले हैं जहां एक रणनीति पैटर्न समग्र कोड की स्थिरता में सुधार कर सकता है। उदाहरण के लिए:

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

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

यह सब नीचे आता है अगर "कर गणना एल्गोरिदम" को मुख्य तर्क से अलग किया जा सकता है जो इसे लागू करता है। एक रणनीति पैटर्न की तुलना में कुछ ओवरहेड होता है if/else, इसलिए आपको निवेश के लायक होने पर केस के आधार पर निर्णय लेना होगा।

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