2012-05-20 21 views
18

मुझे यह कोड ऑनलाइन मिला है जिसमें एक प्रक्रिया के भीतर एक प्रक्रिया है। मुझे समझ में नहीं आ रहा है कि लेखक इसे इस तरह लिखने के लिए क्यों चुना होगा। मैं जो नोटिस करता हूं वह एक पुनरावर्ती कार्य निष्पादित किया जा रहा है।प्रक्रिया के अंदर प्रक्रिया?

उन्होंने मेरे द्वारा देखे गए अधिकांश कोड जैसी प्रक्रियाओं को अलग क्यों नहीं किया।

उनके कार्यान्वयन:

procedure XML2Form(tree : TJvPageListTreeView; XMLDoc : TXMLDocument); 
var 
    iNode : IXMLNode; 

    procedure ProcessNode(
    Node : IXMLNode; 
    tn : TTreeNode); 
    var 
    cNode : IXMLNode; 
    begin 
    if Node = nil then Exit; 
    with Node do 
    begin 
     tn := tree.Items.AddChild(tn, Attributes['text']); 
     tn.ImageIndex := Integer(Attributes['imageIndex']); 
     tn.StateIndex := Integer(Attributes['stateIndex']); 
    end; 

    cNode := Node.ChildNodes.First; 
    while cNode <> nil do 
    begin 
     ProcessNode(cNode, tn); 
     cNode := cNode.NextSibling; 
    end; 
    end; (*ProcessNode*) 
begin 
    tree.Items.Clear; 
    XMLDoc.FileName := ChangeFileExt(ParamStr(0),'.XML'); 
    XMLDoc.Active := True; 

    iNode := XMLDoc.DocumentElement.ChildNodes.First; 

    while iNode <> nil do 
    begin 
    ProcessNode(iNode,nil); 
    iNode := iNode.NextSibling; 
    end; 
    XMLDoc.Active := False; 
end; (* XML2Form *) 


procedure Form2XML(tree: TJVPageListTreeView); 
var 
    tn : TTreeNode; 
    XMLDoc : TXMLDocument; 
    iNode : IXMLNode; 

    procedure ProcessTreeItem(
    tn : TTreeNode; 
    iNode : IXMLNode); 
    var 
    cNode : IXMLNode; 
    begin 
    if (tn = nil) then Exit; 
    cNode := iNode.AddChild('item'); 
    cNode.Attributes['text'] := tn.Text; 
    cNode.Attributes['imageIndex'] := tn.ImageIndex; 
    cNode.Attributes['stateIndex'] := tn.StateIndex; 
    cNode.Attributes['selectedIndex'] := tn.SelectedIndex; 

    //child nodes 
    tn := tn.getFirstChild; 
    while tn <> nil do 
    begin 
     ProcessTreeItem(tn, cNode); 
     tn := tn.getNextSibling; 
    end; 
    end; (*ProcessTreeItem*) 
begin 
    XMLDoc := TXMLDocument.Create(nil); 
    XMLDoc.Active := True; 
    iNode := XMLDoc.AddChild('tree2xml'); 
    iNode.Attributes['app'] := ParamStr(0); 

    tn := tree.TopItem; 
    while tn <> nil do 
    begin 
    ProcessTreeItem (tn, iNode); 

    tn := tn.getNextSibling; 
    end; 

    XMLDoc.SaveToFile(ChangeFileExt(ParamStr(0),'.XML')); 
    XMLDoc := nil; 
end; (* Form2XML *) 

या संशोधित कार्यान्वयन: यह संदर्भ देता tree है, जो मुख्य विधि के लिए एक पैरामीटर है:

procedure ProcessNode(Node : IXMLNode; tn : TTreeNode); 
var 
    cNode : IXMLNode; 
begin 
    if Node = nil then Exit; 
    with Node do 
    begin 
    tn := tree.Items.AddChild(tn, Attributes['text']); 
    tn.ImageIndex := Integer(Attributes['imageIndex']); 
    tn.StateIndex := Integer(Attributes['stateIndex']); 
    end; 

    cNode := Node.ChildNodes.First; 
    while cNode <> nil do 
    begin 
    ProcessNode(cNode, tn); 
    cNode := cNode.NextSibling; 
    end; 
end; (*ProcessNode*) 

procedure ProcessTreeItem(tn : TTreeNode; iNode : IXMLNode); 
var 
    cNode : IXMLNode; 
begin 
    if (tn = nil) then Exit; 
    cNode := iNode.AddChild('item'); 
    cNode.Attributes['text'] := tn.Text; 
    cNode.Attributes['imageIndex'] := tn.ImageIndex; 
    cNode.Attributes['stateIndex'] := tn.StateIndex; 
    cNode.Attributes['selectedIndex'] := tn.SelectedIndex; 

    //child nodes 
    tn := tn.getFirstChild; 
    while tn <> nil do 
    begin 
    ProcessTreeItem(tn, cNode); 
    tn := tn.getNextSibling; 
    end; 
end; (*ProcessTreeItem*) 

procedure XML2Form(tree : TJvPageListTreeView; XMLDoc : TXMLDocument); 
var 
    iNode : IXMLNode; 
begin 
    tree.Items.Clear; 
    XMLDoc.FileName := ChangeFileExt(ParamStr(0),'.XML'); 
    XMLDoc.Active := True; 

    iNode := XMLDoc.DocumentElement.ChildNodes.First; 

    while iNode <> nil do 
    begin 
    ProcessNode(iNode,nil); 
    iNode := iNode.NextSibling; 
    end; 
    XMLDoc.Active := False; 
end; 

procedure Form2XML(tree: TJVPageListTreeView); 
var 
    tn : TTreeNode; 
    XMLDoc : TXMLDocument; 
    iNode : IXMLNode; 
begin 
    XMLDoc := TXMLDocument.Create(nil); 
    XMLDoc.Active := True; 
    iNode := XMLDoc.AddChild('tree2xml'); 
    iNode.Attributes['app'] := ParamStr(0); 

    tn := tree.TopItem; 
    while tn <> nil do 
    begin 
    ProcessTreeItem (tn, iNode); 

    tn := tn.getNextSibling; 
    end; 

    XMLDoc.SaveToFile(ChangeFileExt(ParamStr(0),'.XML')); 
    XMLDoc := nil; 
end; (* Form2XML *) 
+4

यह प्रश्न "पास्कल पास्कल की तरह क्यों है, और सी की तरह नहीं?" तक उबाल जाता है। :-) फिर भी मैं बंद करने के लिए मतदान नहीं कर रहा हूं क्योंकि यह एक वैध नया उपयोगकर्ता प्रश्न है। –

+2

आप उन्हें वैश्विक बनाने की बजाय अपनी प्रक्रिया में चर घोषित क्यों करेंगे? मैं इस प्रक्रिया का उपयोग कभी-कभी अपनी प्रक्रियाओं में प्रक्रियाओं का उपयोग करने के लिए करता हूं, न कि एक और वैश्विक। –

उत्तर

16

इस तरह की नेस्टेड प्रक्रियाएं इस एक्सएमएल से संबंधित कोड में समझ में आती हैं। सभी नोड्स को संसाधित करने के लिए, रिकर्सिव कॉलProcessNode की आवश्यकता है। आपको ध्यान रखना होगा कि कभी-कभी, आंतरिक कार्यों को कुछ पैरामीटर की तुलना में बहुत अधिक डेटा तक पहुंचने की आवश्यकता होती है।

संभावित कार्यान्वयन हो सकता है:

  • उपयोग "फ्लैट" प्रक्रियाओं, अपने कार्यान्वयन में के रूप में;
  • मूल कार्यान्वयन के रूप में "नेस्टेड" प्रक्रियाओं का उपयोग करें;
  • एक समर्पित class (या record + विधियां) बनाएं जो निजी इकाई के implementation भाग में रहेगा।

बेशक, तीसरा विकल्प अधिक रखरखाव लगता है।यह प्रक्रिया के स्पष्ट पृथक्करण की अनुमति देगा, और उनके तरीकों से स्थानीय चर के उपयोग की अनुमति देता है। डेल्फी के पुराने संस्करणों के लिए record (या object) का उपयोग करके प्रोसेसिंग ऑब्जेक्ट को मुख्य प्रक्रिया के ढेर पर आवंटित करने की अनुमति होगी, इसलिए आपको Obj := TInterType.Create; try .. finally Obj.Free लिखने की आवश्यकता नहीं होगी। लेकिन यदि आप object का उपयोग करते हैं तो कृपया ध्यान दें कि डेल्फी has compilation issue का कुछ नया संस्करण - आपको विधियों के साथ record का बेहतर उपयोग करना चाहिए।

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

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

डेल्फी आईडीई और आंतरिक डीबगर नेस्टेड प्रक्रियाओं को अच्छी तरह से संभालती है। IMHO यह कोड के कुछ छोटे टुकड़े (यानी, एक ही स्क्रीन ऊंचाई पर पढ़ा जा सकता है) के लिए समझ में आता है। फिर, जब आपको अधिक प्रक्रिया की आवश्यकता होती है, तो विधियों और स्पष्ट चर के साथ एक समर्पित record/object अधिक रखरखाव योग्य होगा। लेकिन "फ्लैट" विकल्प आईएमएचओ को कोडित नहीं किया जाना है।

मैंने सिर्फ written a blog article about these implementation patterns है, जो एक quicksort कार्यान्वयन, जो यथासंभव कम ढेर अंतरिक्ष का उपयोग करेगा के कुछ स्रोत कोड पेश करेंगे, और एक प्रक्रिया के अंदर एक नेस्टेड प्रक्रिया के लिए एक कॉल से बचने के लिए, और एक समर्पित का उपयोग इसके बजाय निजी object

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

कक्षाएं न केवल इकाई के बाहर आपकी प्रक्रिया को प्रकाशित करने के लिए हैं: ओओपी कार्यान्वयन पैटर्न पर भी लागू होता है। आपका कोड अधिक रखरखाव योग्य होगा, और अधिकांश मामलों में, self पैरामीटर का उपयोग सभी संबंधित डेटा को एक बार में संदर्भित करने के लिए किया जाएगा, इसलिए आपका कोड भी तेज और हल्का हो सकता है!

4

अपने संशोधित संस्करण के साथ एक समस्या नहीं है। यह एक चीज है जिसे नेस्टेड प्रक्रियाओं के साथ पूरा किया जा सकता है: वे अब तक घोषित बाहरी क्षेत्रों से किसी भी चर का उपयोग कर सकते हैं।

यह कहकर कि, बहुत से डेवलपर्स नेस्टेड प्रक्रियाओं को एक गन्दा कोडिंग शैली के रूप में ढूंढते हैं और इससे बचने के लिए पसंद करते हैं; वे आम तौर पर आपके जैसा ही लिखते थे, लेकिन पर एक और पैरामीटर के रूप में tree जोड़ें।

+0

+1 मुझे घोंसले की प्रक्रियाओं को गन्दा नहीं लगता है, जब तक कि वे लंबे न हों, एक छोटी रिकर्सिव प्रक्रिया ट्रिलियन बक्स के लायक है! (: – ComputerSaysNo

+3

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

11

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

एक आंतरिक प्रक्रिया को परिभाषित करने से भविष्य के प्रोग्रामर गलती से आंतरिक प्रक्रिया को बुलाते हैं और इसे कुछ उचित करने की उम्मीद करते हैं। उस आंतरिक प्रक्रिया को भी परिभाषित नहीं किया जाता है - जिसे बाहरी/वैश्विक स्तर पर नहीं कहा जा सकता है।

आंतरिक प्रक्रिया को परिभाषित करने का अर्थ बाहरी/वैश्विक नामस्थान में नाम टक्कर का कम मौका भी है, क्योंकि आंतरिक दिनचर्या उस नामस्थान में कुछ भी योगदान नहीं देती है। (यह एक उत्कृष्ट उदाहरण है: "प्रोसेस नोड (...)" नामक कितनी अलग-अलग चीजें हैं?

और जैसा कि उल्लेख किया गया है, अधिकांश भाषाओं में आंतरिक दिनचर्या में "विशेष" पहुंच होती है जो अन्यथा अदृश्य हो जाती है स्थानीय डेटा प्रकार और चर।

1

ओओपी को इसमें शामिल होने से पहले डेल्फी में नेस्टेड प्रक्रियाएं/कार्य उपलब्ध हैं। यह सब लगभग 25 साल पहले हुआ था। उस समय वापस, एक समारोह के अंदर स्थानीय कार्यों ने वैश्विक दायरे क्लीनर और संबंधित कोड को एक साथ रखने में मदद की। बोर्लैंड/इनप्राइज/एम्बरकेडेरो ने उस सुविधा को कभी भी नहीं छोड़ा, अन्यथा वे एक बड़ी असंगतता पैदा कर सकते थे। तो इसका उपयोग करें यदि यह आपको समझ में आता है, अन्यथा बस इसे होने दें।

+0

कृपया एक उत्तर प्रारूपित करने का प्रयास करें ताकि यह अधिक पठनीय हो जा सके। – Naddy

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