DRY सिद्धांत की व्याख्या


10

अभी मैं अपनी कोडिंग में DRY (डोंट रिपीट योरसेल्फ) की इस अवधारणा से जूझ रहा हूं। मैं यह फ़ंक्शन बना रहा हूं जिसमें मुझे डर है कि यह बहुत जटिल हो रहा है, लेकिन मैं DRY सिद्धांत का पालन करने की कोशिश कर रहा हूं।

createTrajectoryFromPoint(A a,B b,C c,boolean doesSomething,boolean doesSomething2)

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

तो मेरा प्रश्न यह है कि क्या अलग-अलग कार्यों का एक समूह होना बेहतर है जो एक ही तर्क का एक बहुत कुछ साझा करते हैं (इसलिए DRY सिद्धांत का उल्लंघन करते हैं) या एक फ़ंक्शन जो थोड़ा अलग तरीके से दिए गए कई मापदंडों को व्यवहार करता है लेकिन इसे और अधिक जटिल बनाता है (लेकिन संरक्षण DRY)?


3
क्या साझा / आम तर्क को निजी कार्यों में विभाजित किया जा सकता है जो विभिन्न सार्वजनिक createTrajectory...कार्यों को कहते हैं?
FrustratedWithFormsDesigner

यह हो सकता है, लेकिन उन निजी कार्यों को अभी भी उन बूलियन मापदंडों को प्राप्त करने की आवश्यकता होगी
अल्बिनोसर्डफ़िश

2
मुझे लगता है कि इस तरह के ठोस उदाहरण दिए जाने का जवाब देना आसान होगा। मेरी तत्काल प्रतिक्रिया यह है कि आप जो चित्रण दिखा रहे हैं वह पूरी तरह से वास्तविक नहीं है - यानी, वे केवल दो विकल्प नहीं हैं। एक तरफ के रूप में, मैं booleanएक पैरामीटर के रूप में किसी भी उपयोग के बारे में विचार करूंगा ।
जेरी कॉफिन


उह, आप सशर्त चीजों को अपने कार्यों में क्यों नहीं लगा रहे हैं?
ऋग्वेद

जवाबों:


19

एक समारोह / विधि में विभिन्न कोड पथ को ट्रिगर करने के लिए बूलियन तर्क एक भयानक कोड गंध है

आप जो कर रहे हैं वह लूज़ कपलिंग और उच्च सामंजस्य और एकल उत्तरदायित्व सिद्धांतों का उल्लंघन करता है , जो पूर्वाग्रह में DRY से बहुत अधिक महत्वपूर्ण हैं

इसका मतलब है कि चीजों को अन्य चीजों पर निर्भर होना चाहिए, जब उन्हें ( युग्मन ) करना है और उन्हें एक काम करना चाहिए और केवल एक चीज (बहुत अच्छी) ( सामंजस्य ) करना चाहिए।

आपकी अपनी चूक से, यह बहुत कसकर युग्मित है (सभी बूलियन झंडे एक प्रकार की राज्य निर्भरता है, जो सबसे खराब में से एक है!) और बहुत अधिक व्यक्तिगत जिम्मेदारियां हैं जो परस्पर जुड़ी हुई हैं (अत्यधिक जटिल)।

आप जो कर रहे हैं वह वैसे भी DRY की भावना में नहीं है। DRY दोहराव ( Rस्टैंड्स फॉर REPEAT) के बारे में अधिक है । कॉपी और पेस्ट करने से बचना इसका सबसे बुनियादी रूप है। आप जो कर रहे हैं वह पुनरावृत्ति से संबंधित नहीं है।

आपकी समस्या आपके कोड का आपका अपघटन सही स्तर पर नहीं है। यदि आपको लगता है कि आपके पास डुप्लिकेट कोड होगा, तो उसका अपना फ़ंक्शन / तरीका होना चाहिए जो कि उपयुक्त हो, न कि कॉपी और पेस्ट किया गया हो, और अन्य को विवरणात्मक रूप से नामित किया जाए और कोर फ़ंक्शन / विधि में प्रत्यायोजित किया जाए।


ठीक है, ऐसा लगता है कि जिस तरह से मैं लिख रहा हूं वह बहुत अच्छा नहीं है (मेरा प्रारंभिक संदेह) मुझे वास्तव में यकीन नहीं है कि यह 'स्प्रिट ऑफ
डीआरवाई


4

तथ्य यह है कि आप कार्य करने के लिए बूलियनों में गुजर रहे हैं अलग-अलग चीजें एकल जिम्मेदारी सिद्धांत का उल्लंघन है। एक कार्य एक काम करना चाहिए। यह केवल एक काम करना चाहिए, और इसे अच्छी तरह से करना चाहिए।

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

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

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


3

आप अपने कार्य में सभी तर्क युक्त एक और फ़ंक्शन क्यों नहीं बनाएंगे, इससे पहले कि आप कुछ या कुछ करने का निर्णय लें और फिर तीन कार्य करें जैसे:

createTrajectoryFromPoint(A a,B b,C c){...}

dosomething(A a, B b, C c){...}

dosomething2(A a, B b, C c){...}

और अब तीन अलग-अलग कार्यों के लिए एक ही पैरामीटर प्रकार पास करके, आप फिर से अपने आप को दोहराएंगे, इसलिए आपको ए, बी, सी युक्त एक संरचना या वर्ग को परिभाषित करना चाहिए।

वैकल्पिक रूप से आप एक वर्ग बना सकते हैं जिसमें ए, बी, सी और परिचालनों की सूची होगी। आप इन मापदंडों (A, B, C) को ऑब्जेक्ट के साथ पंजीकृत करके कौन से ऑपरेशन (कुछ, कुछ) जोड़ना चाहते हैं। फिर अपनी ऑब्जेक्ट पर सभी पंजीकृत ऑपरेशन को कॉल करने का एक तरीका है।

public class MyComplexType
{
    public A a{get;set;}
    public B b{get;set;}
    public C c{get;set;}

    public delegate void Operation(A a, B b, C c);
    public List<Operation> Operations{get;set;}

    public MyComplexType(A a, B b, C c)
    {
        this.a = a;
        this.b = b;
        this.c = c   
        Operations = new List<Operation>();
    }

    public CallMyOperations()
    {
        foreach(var operation in Operations)
        {
            operation(a,b,c);
        }
    }
}

बेस डोजोमेटिंग और डोसोमेले 2 के लिए मूल्यों के संभावित संयोजनों के लिए खाता बनाने के लिए, आपको आधार क्रिएटट्रीफ्रीफ्रेमप्वाइंट फ़ंक्शन के अलावा 4 कार्यों की आवश्यकता होगी, 2 नहीं। यह दृष्टिकोण ठीक नहीं है क्योंकि विकल्पों की संख्या बढ़ जाती है, और यहां तक ​​कि फ़ंक्शन का नामकरण थकाऊ हो जाता है।
JGWeissman

2

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


1

मैं आमतौर पर इस समस्या के साथ कई चरणों से गुजरता हूं, जब यह पता लगाना बंद हो जाता है कि आगे कैसे जाना है।

सबसे पहले, आपने जो किया है। DRY के साथ मेहनत करो। यदि आप एक बड़े बालों वाली गंदगी के साथ समाप्त नहीं होते हैं, तो आप कर रहे हैं। यदि, आपके मामले में, आपके पास कोई डुप्लिकेट कोड नहीं है, लेकिन प्रत्येक बूलियन का मूल्य 20 अलग-अलग स्थानों पर चेक किया गया है, तो अगले चरण पर जाएं।

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

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

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


0

एक वैकल्पिक दृष्टिकोण इंटरफ़ेस मापदंडों के साथ बूलियन मापदंडों को बदलने के लिए है, इंटरफ़ेस बस्तियों में परिलक्षित विभिन्न बूलियन मूल्यों को संभालने के लिए कोड के साथ। तो आपके पास होता

createTrajectoryFromPoint(A a,B b,C c,IX x,IY y)

जहां आपके पास IX और IY के कार्यान्वयन हैं जो बूलियंस के लिए विभिन्न मूल्यों का प्रतिनिधित्व करते हैं। फ़ंक्शन के शरीर में, जहां भी आपके पास है

if (doesSomething)
{
     ...
}
else
{
     ...
}

आप इसे IX पर परिभाषित विधि के लिए एक कॉल के साथ छोड़ देते हैं, जिसमें लोप किए गए कोड ब्लॉक वाले कार्यान्वयन होते हैं।

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