2008-12-04 17 views
136

यह "निष्पादन" के आसपास क्या है (या इसी तरह) मैं किस बारे में सुन रहा हूं? मैं इसका उपयोग क्यों कर सकता हूं, और मैं इसका उपयोग क्यों नहीं करना चाहूंगा?मुहावरे "निष्पादन" क्या है?

+9

मैंने नहीं देखा था कि यह आप थे, tack। अन्यथा मैं अपने उत्तर में अधिक व्यंग्यात्मक हो सकता था;) –

+1

तो यह मूल रूप से _aspect_ सही है? यदि नहीं, तो यह अलग कैसे होता है? – Lucas

उत्तर

129

असल में यह वह पैटर्न है जहां आप हमेशा ऐसी चीजें करने के लिए एक विधि लिखते हैं जो हमेशा आवश्यक होती है, उदा। संसाधन आवंटन और साफ-सफाई, और कॉलर को "संसाधन के साथ हम क्या करना चाहते हैं" में पास करते हैं। उदाहरण के लिए:

public interface InputStreamAction 
{ 
    void useStream(InputStream stream) throws IOException; 
} 

// Somewhere else  

public void executeWithFile(String filename, InputStreamAction action) 
    throws IOException 
{ 
    InputStream stream = new FileInputStream(filename); 
    try { 
     action.useStream(stream); 
    } finally { 
     stream.close(); 
    } 
} 

// Calling it 
executeWithFile("filename.txt", new InputStreamAction() 
{ 
    public void useStream(InputStream stream) throws IOException 
    { 
     // Code to use the stream goes here 
    } 
}); 

// Calling it with Java 8 Lambda Expression: 
executeWithFile("filename.txt", s -> System.out.println(s.read())); 

// Or with Java 8 Method reference: 
executeWithFile("filename.txt", ClassName::methodName); 

बुला कोड खुला/सफाई पक्ष के बारे में चिंता की जरूरत नहीं है - यह executeWithFile द्वारा ध्यान रखा जाएगा।

यह जावा में स्पष्ट रूप से दर्दनाक था क्योंकि बंदरगाह इतने शब्दपूर्ण थे, जावा 8 लैम्ब्डा अभिव्यक्तियों से शुरू होने से कई अन्य भाषाओं (जैसे सी # लैम्ब्डा एक्सप्रेशन, या ग्रोवी) में लागू किया जा सकता है, और यह विशेष मामला जावा 7 के बाद से संभाला जाता है try-with-resources और AutoClosable धाराएं।

हालांकि "आवंटित और साफ-सफाई" सामान्य उदाहरण दिया गया है, लेकिन कई अन्य संभावित उदाहरण हैं - लेनदेन हैंडलिंग, लॉगिंग, अधिक विशेषाधिकारों के साथ कुछ कोड निष्पादित करना आदि। यह मूल रूप से template method pattern जैसा है लेकिन विरासत के बिना।

+0

यह एक निर्माता और अवरोधक से अलग कैसे है जो प्रारंभिकरण और आंसू को नियंत्रित करता है? – Nathan

+4

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

+2

तो यह सी में जैसा है जहां आपके पास कोई फ़ंक्शन है जो आप फ़ंक्शन पॉइंटर में कुछ काम करने के लिए पास करते हैं? –

5

एक Execute Around Method वह जगह है जहां आप किसी विधि के लिए मनमानी कोड पास करते हैं, जो सेटअप और/या टियरडाउन कोड कर सकता है और आपके कोड को बीच में निष्पादित कर सकता है।

जावा वह भाषा नहीं है जिसे मैं ऐसा करने के लिए चुनूंगा। यह एक बंद (या लैम्ब्डा अभिव्यक्ति) को तर्क के रूप में पारित करने के लिए और अधिक स्टाइलिश है। हालांकि वस्तुओं तर्कसंगत equivalent to closures हैं।

ऐसा लगता है कि विधि के आसपास निष्पादन Inversion of Control (निर्भरता इंजेक्शन) जैसा है, जब भी आप विधि को कॉल करते हैं, तो आप विज्ञापन बदल सकते हैं।

लेकिन इसे नियंत्रण युग्मन के उदाहरण के रूप में भी व्याख्या किया जा सकता है (एक विधि बता रहा है कि इसके तर्क से क्या करना है, सचमुच इस मामले में)।

42

निष्पादित मुहावरा के आसपास जब आप पाते हैं अपने आप को कुछ इस तरह क्या करने वाले प्रयोग किया जाता है:

//... chunk of init/preparation code ... 
task A 
//... chunk of cleanup/finishing code ... 

//... chunk of identical init/preparation code ... 
task B 
//... chunk of identical cleanup/finishing code ... 

//... chunk of identical init/preparation code ... 
task C 
//... chunk of identical cleanup/finishing code ... 

//... and so on.

आदेश में इस निरर्थक कोड है कि हमेशा "के आसपास" को अपने वास्तविक कार्य निष्पादित किया जाता है के सभी दोहरा बचने के लिए, आप एक वर्ग है कि स्वचालित रूप से इसे का ख्याल रखता है बनाना होगा: (! और पोषणीय)

//pseudo-code: 
class DoTask() 
{ 
    do(task T) 
    { 
     // .. chunk of prep code 
     // execute task T 
     // .. chunk of cleanup code 
    } 
}; 

DoTask.do(task A) 
DoTask.do(task B) 
DoTask.do(task C)

यह मुहावरा एक स्थान पर ले जटिल अनावश्यक कोड के सभी चलता है, और भी बहुत कुछ पठनीय अपने मुख्य कार्यक्रम छोड़ देता है

सी # उदाहरण के लिए this post पर एक सी ++ उदाहरण के लिए this article पर एक नज़र डालें।

7

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

विचार यह है कि कभी-कभी आपके पास कोड होता है जो कोड चलाने से पहले और कोड चलाने के बाद हमेशा उसी बॉयलरप्लेट को शामिल करता है। एक अच्छा उदाहरण जेडीबीसी है। वास्तविक क्वेरी चलाने और परिणाम सेट को संसाधित करने से पहले आप हमेशा एक कनेक्शन लेते हैं और एक कथन (या तैयार कथन) बनाते हैं, और फिर आप हमेशा अंत में एक ही बॉयलरप्लेट क्लीनअप करते हैं - कथन और कनेक्शन को बंद करते हैं।

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

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

आप जावा में कुछ सामान्य मामलों से परिचित हो सकते हैं। एक सर्वलेट फिल्टर है। सलाह के चारों ओर एक और एओपी है। वसंत में एक तिहाई विभिन्न xxx टेम्पलेट वर्ग है। प्रत्येक मामले में आपके पास कुछ रैपर ऑब्जेक्ट होता है जिसमें आपका "रोचक" कोड (जेडीबीसी क्वेरी और परिणाम सेट प्रोसेसिंग कहता है) इंजेक्शन दिया जाता है। रैपर ऑब्जेक्ट "पहले" भाग करता है, रोचक कोड का आह्वान करता है और फिर "बाद" भाग करता है।

3

यह मुझे strategy design pattern की याद दिलाता है। ध्यान दें कि जिस लिंक को मैंने इंगित किया है वह पैटर्न के लिए जावा कोड शामिल है।

स्पष्ट रूप से कोई प्रारंभिकरण और सफाई कोड बनाकर "निष्पादन" कर सकता है और केवल एक रणनीति में गुजर रहा है, जिसे हमेशा प्रारंभिकरण और सफाई कोड में लपेटा जाएगा।

कोड पुनरावृत्ति को कम करने के लिए उपयोग की जाने वाली किसी भी तकनीक के साथ, आपको इसका उपयोग तब तक नहीं करना चाहिए जब तक आपके पास कम से कम 2 मामले हों, जहां आपको इसकी आवश्यकता हो, शायद 3 (एक ला यागनी सिद्धांत)। ध्यान रखें कि हटाने कोड दोहराव रखरखाव को कम करता है (कोड की कम प्रतियों का मतलब है कि प्रत्येक प्रतिलिपि में फिक्स को कॉपी करने में कम समय व्यतीत होता है), लेकिन रखरखाव (अधिक कुल कोड) भी बढ़ाता है। इस प्रकार, इस चाल की लागत यह है कि आप अधिक कोड जोड़ रहे हैं।

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

0

आप ग्रूवी मुहावरों चाहते हैं, यहाँ यह है:

//-- the target class 
class Resource { 
    def open() { // sensitive operation } 
    def close() { // sensitive operation } 
    //-- target method 
    def doWork() { println "working";} } 

//-- the execute around code 
def static use (closure) { 
    def res = new Resource(); 
    try { 
     res.open(); 
     closure(res) 
    } finally { 
     res.close(); 
    } 
} 

//-- using the code 
Resource.use { res -> res.doWork(); } 
+0

यदि मेरा खुला असफल हो जाता है (एक पुनर्विक्रेता ताला प्राप्त करने का कहना है) को बंद करने के लिए कहा जाता है (मिलान खुले असफल होने के बावजूद एक पुनर्विक्रय लॉक जारी करना)। –

7

भी देखें Code Sandwiches है, जो इस कई प्रोग्रामिंग भाषाओं के पार का निर्माण सर्वेक्षण और कुछ दिलचस्प research'y विचारों प्रदान करता है के संबंध में। इसका कोई सवाल क्यों है कि कोई इसका उपयोग क्यों कर सकता है, उपरोक्त पेपर कुछ ठोस उदाहरण प्रदान करता है:

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

और बाद में:

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

कागज क्यों नहीं इस मुहावरे का उपयोग करने का पता लगाने के नहीं है, लेकिन यह वर्णन करता है क्यों मुहावरा भाषा स्तरीय मदद के बिना गलत पाने के लिए आसान है:

दोषपूर्ण कोड सैंडविच सबसे अधिक बार उठता अपवादों और उनके संबंधित अदृश्य नियंत्रण प्रवाह की उपस्थिति में। दरअसल, कोड सैंडविच प्रबंधित करने के लिए विशेष भाषा विशेषताएं मुख्य रूप से भाषाओं में अपवादों का समर्थन करती हैं।

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

+0

अच्छा बिंदु, azurefrag। मैंने अपना जवाब संशोधित और विस्तारित किया है ताकि यह वास्तव में अपने स्वयं के अधिकार में एक आत्मनिर्भर उत्तर का अधिक हो। इसका सुझाव देने के लिए धन्यवाद। कल्पना के लिए –

3

मैं समझाने के लिए, के रूप में एक चार साल पुराने करने के लिए मैं करूंगा कोशिश करता हूँ:

उदाहरण 1

सांता शहर में आ रहा। उनके कल्पित बौने कोड जो कुछ भी वे अपनी पीठ के पीछे चाहते हैं, और जब तक वे बदल बातें एक छोटे से दोहराए मिलती है:

  1. लपेटकर कागज
  2. जाओ सुपर Nintendo प्राप्त करें।
  3. इसे लपेटें।

या इस:

  1. लपेटकर कागज
  2. जाओ बार्बी गुड़िया प्राप्त करें।
  3. इसे लपेटें।

.... विज्ञापन लाखों अलग-अलग उपहारों के साथ लाखों बार मत करो: ध्यान दें कि केवल एक ही चीज अलग है 2. यदि चरण दो एकमात्र चीज है जो अलग है, तो सांता कोड को डुप्लिकेट क्यों कर रहा है, यानी वह चरण 1 और 3 दस लाख बार क्यों डुप्लिकेट कर रहा है? एक मिलियन उपहार का मतलब है कि वह अनिवार्य रूप से कदम 1 और 3 लाखों बार दोहरा रहा है।

निष्पादन उस समस्या को हल करने में मदद करता है। और कोड को खत्म करने में मदद करता है। चरण 1 और 3 मूल रूप से निरंतर हैं, चरण 2 के लिए एकमात्र हिस्सा होने की अनुमति देता है जो बदलता है।

उदाहरण # 2

आप अभी भी इसे नहीं मिलता है, यहाँ एक और उदाहरण है: एक सैंडविच के बारे में सोच: बाहर की दुनिया में रोटी हमेशा एक ही है, लेकिन बातों के आधार पर अंदर परिवर्तन पर है आपके द्वारा चुने गए सैंडविच का प्रकार (.eg हैम, पनीर, जाम, मूंगफली का मक्खन आदि)। रोटी हमेशा बाहर होती है और आपको हर प्रकार के सैंडविच के लिए एक बिलियन बार दोहराने की आवश्यकता नहीं होती है।

अब यदि आप उपर्युक्त स्पष्टीकरण पढ़ते हैं, तो शायद आपको समझना आसान लगेगा। मुझे आशा है कि इस स्पष्टीकरण ने आपकी मदद की है।

+0

+ डी – hedgehog

संबंधित मुद्दे