क्या यह एक अच्छा पैटर्न है: लम्बोदा की श्रृंखला के साथ एक लंबे फ़ंक्शन को प्रतिस्थापित करना?


14

मैं हाल ही में निम्न स्थिति में चला गया।

class A{
public:
    void calculate(T inputs);
}

सबसे पहले, Aभौतिक दुनिया में एक वस्तु का प्रतिनिधित्व करता है, जो वर्ग को विभाजित नहीं करने के लिए एक मजबूत तर्क है। अब, calculate()काफी लंबा और जटिल कार्य हो गया है। मैं इसके लिए तीन संभावित संरचनाएं देखता हूं:

  • इसे पाठ की दीवार के रूप में लिखें - लाभ - सभी जानकारी एक ही स्थान पर है
  • privateकक्षा में उपयोगिता कार्यों को लिखें और उन्हें calculateशरीर में उपयोग करें - नुकसान - उन तरीकों के बारे में बाकी कक्षा को पता नहीं है / देखभाल / समझ नहीं है
  • calculateनिम्नलिखित तरीके से लिखें :

    void A::calculate(T inputs){    
        auto lambda1 = () [] {};    
        auto lambda2 = () [] {};    
        auto lambda3 = () [] {};
    
        lambda1(inputs.first_logical_chunk);
        lambda2(inputs.second_logical_chunk);
        lambda3(inputs.third_logical_chunk);
    }
    

क्या यह एक अच्छा या बुरा अभ्यास माना जा सकता है? क्या यह दृष्टिकोण किसी भी समस्या को प्रकट करता है? सब के सब, मैं एक अच्छा दृष्टिकोण के रूप में इस पर विचार करना चाहिए जब मैं फिर से उसी स्थिति का सामना कर रहा हूं?


संपादित करें:

class A{
    ...
public:
    // Reconfiguration of the algorithm.
    void set_colour(double colour);
    void set_density(double density);
    void set_predelay(unsigned long microseconds);
    void set_reverb_time(double reverb_time, double room_size);
    void set_drywet(double left, double right);
    void set_room_size(double value);;

private:
    // Sub-model objects.
    ...
}

वे सभी विधियाँ:

  • एक मूल्य प्राप्त करें
  • राज्य का उपयोग किए बिना, कुछ अन्य मूल्यों की गणना करें
  • अपने राज्य को बदलने के लिए "उप-मॉडल ऑब्जेक्ट्स" में से कुछ को कॉल करें।

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

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


2
यह क्या है आपको लगता है कि लैम्ब्डा का उपयोग करने से आपको मिल जाएगा कि फ़ंक्शन कॉल नहीं होगा?
ब्लरफाल

1
Firstly, A represents an object in the physical world, which is a strong argument for not splitting the class up.भौतिक दुनिया में मौजूद किसी वस्तु के बारे में निश्चित रूप से डेटा काA प्रतिनिधित्व करता है। आप उदाहरण के बिना वास्तविक वस्तु और वास्तविक वस्तु के बिना एक उदाहरण हो सकते हैं , इसलिए उनके साथ ऐसा व्यवहार करना कि वे एक हैं और एक ही निरर्थक है। AA
डोभाल

@ बेलफ्रेम, एनकैप्सुलेशन - कोई भी नहीं लेकिन calculate()उन उप-कार्यों के बारे में पता चलेगा।
वोराक

यदि उन सभी गणनाओं के लिए प्रासंगिक हैं A, तो यह थोड़ा चरम पर ले जा रहा है।
Blrfl

1
"सबसे पहले, Aभौतिक दुनिया में एक वस्तु का प्रतिनिधित्व करता है, जो कक्षा को विभाजित नहीं करने के लिए एक मजबूत तर्क है।" जब मैंने प्रोग्रामिंग शुरू की तो दुर्भाग्य से मैंने यह बताया था। मुझे यह महसूस करने में वर्षों लग गए कि यह हॉर्स हॉकी का एक गुच्छा है। चीजों को समूहित करना एक भयानक कारण है। मैं स्पष्ट नहीं कर सकता कि समूह की चीजों के लिए अच्छे कारण क्या हैं (कम से कम मेरी संतुष्टि के लिए), लेकिन वह वह है जिसे आपको अभी त्याग देना चाहिए। अंत सब, "अच्छे कोड" के सभी हो सकते हैं कि यह सही काम करता है, समझने में अपेक्षाकृत आसान है, और बदलना अपेक्षाकृत आसान है (यानी, बदलावों के अजीब दुष्प्रभाव नहीं हैं)।
jpmc26

जवाबों:


13

नहीं, यह आम तौर पर एक अच्छा पैटर्न नहीं है

आप जो कर रहे हैं वह लंबोदा का उपयोग करके एक फ़ंक्शन को छोटे कार्यों में तोड़ रहा है। हालांकि, वहाँ एक है बहुत कार्यों को तोड़ने के लिए बेहतर उपकरण: कार्य करता है।

लैम्ब्डा काम करते हैं, जैसा कि आपने देखा है, लेकिन वे बहुत अधिक मतलब है कि स्थानीय बिट्स में एक फ़ंक्शन को तोड़ने की तुलना में बहुत अधिक है। लम्बदास करते हैं:

  • बंद। आप लैम्बडा के अंदर बाहरी दायरे में चर का उपयोग कर सकते हैं। यह बहुत शक्तिशाली और बहुत जटिल है।
  • पुनः सौंपा जाना। जबकि आपका उदाहरण असाइनमेंट करना कठिन बनाता है, किसी को हमेशा इस विचार पर ध्यान देना होगा कि कोड किसी भी समय फ़ंक्शन को स्वैप कर सकता है।
  • प्रथम श्रेणी के कार्य। आप एक अन्य समारोह में एक लंबोतरा फ़ंक्शन पास कर सकते हैं, जिसे "कार्यात्मक प्रोग्रामिंग" के रूप में जाना जाता है।

तुरंत आप लैंबडास को मिक्स में लाते हैं, कोड को देखने के लिए अगले डेवलपर को तुरंत उन सभी नियमों को मानसिक रूप से लोड करना होगा जो यह देखने के लिए तैयार हैं कि आपका कोड कैसे काम करता है। वे नहीं जानते कि आप उस सभी कार्यक्षमता का उपयोग नहीं करने जा रहे हैं। विकल्पों की तुलना में यह बहुत महंगा है।

यह आपकी बागवानी करने के लिए बैक-हो का उपयोग करने जैसा है। आप जानते हैं कि आप केवल इस वर्ष के फूलों के लिए छोटे छेद खोदने के लिए इसका उपयोग कर रहे हैं, लेकिन पड़ोसी घबरा जाएंगे।

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

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

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

void A::set_room_size(double value)
{
    {
        // Part 1: {description of part 1}
        ...
    }
    // ------------------------
    {
        // Part 2: {description of part 2}
        ...
    }
    // ------------------------
    {
        // Part 3: {description of part 3}
        ...
    }
}

इसलिए यह एक वस्तुनिष्ठ संख्या नहीं है, लेकिन मैं इस विषय पर दावा करूंगा कि लैंबडा कार्यों की मात्र उपस्थिति मुझे कोड की प्रत्येक पंक्ति पर लगभग 10 गुना अधिक ध्यान देती है, क्योंकि उनके पास खतरनाक रूप से जटिल, तेज और ऐसा करने की इतनी अधिक क्षमता है। कोड की एक निर्दोष दिखने वाली लाइन (जैसे count++)
Cort Ammon

महान बिंदु। मैं लैम्बदास के साथ दृष्टिकोण के कुछ फायदों के रूप में देखता हूं - (1) कोड स्थानीय रूप से आसन्न और स्थानीय दायरे के साथ (यह फ़ाइल-स्तर के कार्यों से खो जाएगा) (2) संकलक सुनिश्चित करता है कि कोड खंडों के बीच कोई स्थानीय चर साझा नहीं किए जाते हैं। तो उन फायदों calculate()को {}ब्लॉक में अलग करके और calculate()गुंजाइश पर साझा डेटा की घोषणा करके संरक्षित किया जा सकता है । मैंने सोचा था कि यह देखते हुए कि लंबोदर कब्जा नहीं करते हैं, एक पाठक को लंबोदर की शक्ति का सामना नहीं करना पड़ेगा।
वोरैक

"हालांकि मैं यह देख रहा हूं कि लंबोदर को पकड़ना नहीं है, एक पाठक को लंबोदर की ताकत से नहीं घेरा जाएगा।" यह वास्तव में एक निष्पक्ष, लेकिन विवादास्पद कथन है, जो भाषाविज्ञान के दिल पर हमला करता है। शब्दों में आम तौर पर अर्थ होते हैं जो उनके अर्थों से परे होते हैं। चाहे मेरा अनुमान lambdaअनुचित है, या यदि आप लोगों को सख्ती से धर्म का पालन करने के लिए मजबूर कर रहे हैं, तो इसका जवाब देना आसान सवाल नहीं है। वास्तव में, आपकी कंपनी में उस तरह का उपयोग करना आपके लिए पूरी तरह स्वीकार्य हो सकता है lambda, और मेरी कंपनी में पूरी तरह से अस्वीकार्य हो सकता है, और न ही किसी को वास्तव में गलत होना चाहिए!
Cort Ammon

लंबोदर के सानिध्य पर मेरी राय इस तथ्य से उपजी है कि मैं C ++ 03 पर बढ़ा, न कि C + 11। मैं वर्षों के विशिष्ट स्थानों पर जहां सी ++ की कमी से चोट किया गया है के लिए सराहना विकासशील खर्च किया है lambda, जैसे for_eachकार्य करते हैं। तदनुसार, जब मैं देखता हूं lambdaकि यह उन आसान-से-स्पॉट परेशानी के मामलों में से एक में फिट नहीं होता है, तो पहली बार मैं यह मानता हूं कि यह संभवतः कार्यात्मक प्रोग्रामिंग के लिए उपयोग किया जाएगा, क्योंकि इसकी अन्यथा आवश्यकता नहीं थी। कई डेवलपर्स के लिए, कार्यात्मक प्रोग्रामिंग प्रक्रियात्मक या OO प्रोग्रामिंग से पूरी तरह से अलग मानसिकता है।
Cort Ammon

समझाने के लिए धन्यवाद। मैं नौसिखिया प्रोग्रामर हूं और अब मुझे खुशी है कि मैंने पूछा - इससे पहले कि आदत बन गई थी।
वोरैक

20

मुझे लगता है कि आपने एक बुरी धारणा बना ली है:

सबसे पहले, ए भौतिक दुनिया में एक वस्तु का प्रतिनिधित्व करता है, जो कक्षा को विभाजित नहीं करने के लिए एक मजबूत तर्क है।

मैं इससे असहमत हूं। उदाहरण के लिए, यदि मेरे पास एक वर्ग है जो एक कार का प्रतिनिधित्व करता है, तो मैं निश्चित रूप से इसे विभाजित करना चाहूंगा, क्योंकि मैं निश्चित रूप से टायर का प्रतिनिधित्व करने के लिए एक छोटा वर्ग चाहता हूं।

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

मैं वास्तव में इस मामले में लैम्ब्डा कार्यों का उपयोग करने का लाभ नहीं देखता, क्योंकि यह वास्तव में कोड क्लीनर नहीं बनाता है। वे कार्यात्मक शैली प्रोग्रामिंग की सहायता के लिए बनाए गए थे, लेकिन ऐसा नहीं है।

आपने जो लिखा है वह जावास्क्रिप्ट स्टाइल नेस्टेड फंक्शन ऑब्जेक्ट्स से थोड़ा मिलता जुलता है। जो फिर से एक संकेत है कि वे एक साथ कसकर संबंधित हैं। क्या आप निश्चित हैं, कि आपको उनके लिए एक अलग वर्ग नहीं बनाना चाहिए?

संक्षेप में, मुझे नहीं लगता कि यह एक अच्छा पैटर्न है।

अपडेट करें

यदि आपको इस कार्यक्षमता को सार्थक वर्ग में अतिक्रमण करने का कोई तरीका नहीं दिखता है, तो आप फ़ाइल स्कॉप्ड हेल्पर फ़ंक्शन बना सकते हैं, जो आपकी कक्षा के सदस्य नहीं हैं । यह C ++ है सब के बाद, ओओ डिजाइन एक जरूरी नहीं है।


उचित लगता है, लेकिन मेरे लिए कार्यान्वयन की कल्पना करना मुश्किल है। स्थिर तरीकों के साथ फाइल-स्कोप क्लास? वर्ग, अंदर परिभाषित A(शायद अन्य सभी तरीकों के साथ भी मज़ेदार)? कक्षा को घोषित और अंदर परिभाषित किया गया calculate()(यह मेरे लैम्ब्डा उदाहरण की तरह दिखता है)। स्पष्टीकरण के रूप में, calculate()तरीकों ( calculate_1(), calculate_2()आदि) के परिवार में से एक है , जिनमें से सभी सरल हैं, बस यह एक 2 सूत्रों का स्क्रीन है।
वोराक

@Vorac: calculate()अन्य सभी तरीकों की तुलना में बहुत लंबा क्यों है ?
केविन

@ वोरैक आपके कोड को देखे बिना मदद करना वास्तव में कठिन है। क्या आप भी इसे पोस्ट कर सकते हैं?
गैबोर एंगिएल

@ केविन, सब कुछ के लिए सूत्र आवश्यकताओं में दिए गए हैं। कोड पोस्ट किया गया।
वोरैक

4
अगर मैं कर सकता तो मैं इसे 100 गुना बढ़ा देता। "वास्तविक दुनिया में वस्तुओं की मॉडलिंग" ऑब्जेक्ट डिज़ाइन डेथ सर्पिल की शुरुआत है। यह किसी भी कोड में एक विशाल लाल झंडा है।
फ्रेड द मैजिक वंडर डॉग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.