我不明白为什么作者会选择这样写。
我所注意到的是执行的递归函数。
为什么他没有像我看过的大多数代码那样分离过程。
他的实施:
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 *)
或修改实施:
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),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,'.XML')); XMLDoc := nil; end; (* Form2XML *)
解决方法
潜在的实现可能是:
>使用“平”程序,如在您的实现中;
>使用“嵌套”过程,如原来的实现;
>创建一个专用的类(或记录方法),它将保持私有对于该单元的实现部分。
当然,第三个选项听起来更可维护。它将允许清除过程的分离,并允许使用本地方法的变量。使用记录(或旧版本的Delphi对象)将允许处理对象分配在主过程的堆栈上,因此您不需要编写Obj:= TInterType.Create;试试..终于Obj.Free。但是如果你使用一个对象,请注意一些新版本的Delphi has compilation issue – 你应该更好地使用方法记录。
“平面”过程风格是IMHO不比“嵌套”过程更好,更糟糕的是,由于需要向内部调用添加附加参数,或使用一些全局变量。顺便说一下,每次调用都有很多变量会增加堆栈空间,并降低速度。
“嵌套”风格实际上是面向对象的。当调用内部函数时,编译器将寄存器中的调用者堆栈基础传递给嵌套函数(就像对象的附加自参数)。所以内部函数能够访问所有调用者栈变量,就像在私有对象中声明的一样(第三个解决方案)。
Delphi IDE和内部调试器很好地处理嵌套过程。对于一些小的代码(也就是说,在同一个屏幕高度上可以读取的内容),IMHO可能是有意义的。那么,当你需要更多的流程时,具有方法和显式变量的专用记录/对象将更加可维护。但是“平”选项是IMHO不被编码。
我只是written a blog article about these implementation patterns,它将提供QuickSort实现的一些源代码,它将尽可能使用尽可能少的堆栈空间,并且将避免调用过程中的嵌套过程,并改用专用私有对象。
在所有情况下,不要害怕创建一些内部对象/类来实现算法。 Delphi的最新版本甚至允许类定义中的私有类型 – 但是有时候,使内部对象对于单元的实现部分完全是私有的,即使不显示为单元的接口部分的私有成员,我感觉更为舒适。
类不仅用于在单元之外发布过程:OOP也适用于实现模式。您的代码将更加易于维护,在大多数情况下,自身参数将被用于一次性引用所有相关数据,因此您的代码也可能更快更轻!