递归属性(Delphi)

时间:2012-08-13 07:32:17

标签: delphi recursion

我正在编写一个应用程序,该应用程序映射出一个目录结构,该目录结构需要尽可能多地保存有关每个文件的信息,以便最终用户可以应用自定义过滤器来操作其中的文件和文件夹。同时进行文件搜索的类将基本信息提供回UI,以使最终用户了解涉及多少数据。我想要完成的是通过属性递归到类的子对象以获取我需要的信息,这样我只需要访问顶级类就可以获得所需的信息,而不必担心信息在任何数量的子类中。

type 
  TSomeClass = class(TObject)
  private    
    FContainerForSubObjects: TObjectList<TSomeClass>;
    FSomethingToBeCounted: Integer;
    FHasTheDataChanged: Boolean;
  private
    function GetSomethingToBeCounted: Integer;
    function GetHasTheDataChanged: Boolean;
  public
    property SomethingToBeCounted: Integer read GetSomethingToBeCounted;
    property HasTheDataChanged: Boolean read GetHasTheDataChanged;

使类声明更有意义。像这样看待它。 ContainerForSubObjects包含一个文件夹,所以如果您要查看您的硬盘驱动器,根类将是C:\如果有一个名为data的文件夹,则会有一个表示C:\ Data文件夹的子对象和SomethingToBeCounted将是每个文件夹中的文件数。

现在我想在GetSomethingToBeCounted函数中做什么,如下所示

  1. 查看是否有任何子对象(这部分很容易)
  2. 如果有子对象,请查询其SomethingToBeCounted属性,而该属性又应调用GetSomethingToBeCounted函数以返回类 BUT <{1}}字段的值函数应该根据类的FSomethingToBeCounted状态的条件行动这是我希望递归的地方
    • 如果HasTheDataChanged属性设置为false,则任何包含的子对象都是最新的,那么它应该返回它的值,不再需要进行处理
    • 如果HasTheDataChanged属性设置为true,则数据不是最新的,应重新计算并返回新的重新计算值。它还应该设置适当的HasTheDataChanged状态,以减少进一步的重新处理。
  3. 我还假设必须使用HasTheDataChanged属性来完成这种类似的传播,这样如果值在树的中间某处发生变化,所有父对象都会相应地更新。

    希望这些要求有意义

    现在问题的关键。首先。我的想法是正确的,只是通过访问子对象属性,正确的值将传播到根对象,所以当可能有数千个子对象时,我不必花费无数的代码行搜索每个子对象。或者这是我试图在这里重新发明轮子的情况,我只是在寻找一个已经存在的类并且可以使用而不是自己制作。最后但并非最不重要。这会是最有效的做事方式吗?

2 个答案:

答案 0 :(得分:2)

我没有遇到过你想做的事情的现有组件,所以写你自己似乎是合理的。

你的方法会起作用,是我多次使用过的方法。您有一个递归数据结构TSomeClass包含更多TSomeClass个对象的列表。以任何其他方式遍历这个结构会更复杂。

答案 1 :(得分:2)

对于这样的事情,我可能会朝另一个方向前进。我没有让父对象试图找出哪些子对象发生了变化,而是让一个子对象在发生更改时通知其父对象,然后通知其父对象及其父对象,依此类推。让信息向上冒泡,而不是向下搜索。这将大部分工作放在启动更改的活动上,并使搜索速度更快,因为所有信息都预先缓存在树中而无需寻找它。

type  
  TSomeClass = class(TObject) 
  private     
    FParent: TSomeClass; 
    FSubObjects: TObjectList<TSomeClass>; 
    FSomethingToBeCounted: Integer; 
    FHasTheDataChanged: Boolean; 
    procedure Changed; 
  protected
    procedure SubObjectChanged(ASubObject: TSomeClass); 
  public 
    constructor Create(AParent: TSomeClass = nil);
    destructor Destroy; override;
    procedure DoSomethingToMakeAChange;
    property SomethingToBeCounted: Integer read FSomethingToBeCounted; 
    property HasTheDataChanged: Boolean read FHasTheDataChanged; 
  end;

constructor TSomeObject.Create(AParent: TSomeClass = nil);
begin
  inherited Create;
  FParent := AParent;
  FSubObjects := TObjectList<TSomeClass>.Create;
  //...
end;

destructor TSomeClass.Destroy;
begin
  //...
  FSubObjects.Free;
  inherited Destroy;
end;

procedure TSomeObject.DoSomethingToMakeAChange;
begin
  // update FSomethingToBeCounted as needed
  Changed;
end;

procedure TSomeClass.SubObjectChanged(ASubObject: TSomeClass); 
begin
  // update FSomethingToBeCounted as needed, based on which child was changed
  Changed;
end;

procedure TSomeClass.Changed; 
begin
  FHasTheDataChanged := True; 
  if FParent <> nil then
    FParent.SubObjectChanged(Self); 
end;