2

我正在编写一个应用程序,该应用程序映射出一个目录结构,该目录结构需要尽可能多地保存有关每个文件的信息,以便最终用户可以应用自定义过滤器来操作其中的文件和文件夹。还进行文件搜索的类将基本信息返回给 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函数以返回FSomethingToBeCounted类字段的值,该函数应根据HasTheDataChanged类的状态条件进行操作这是我希望递归的地方起作用
    • 如果HasTheDataChanged任何包含的子对象的属性设置为 false 是最新的,那么它应该返回它的值并且不应该进行更多处理
    • 如果HasTheDataChanged属性设置为 true 数据不是最新的,应该重新计算并返回新的重新计算值。它还应该设置适当的HasTheDataChanged状态,以减少进一步的重新处理。

我还假设这种类似类型的传播也必须使用 HasTheDataChanged 属性来完成,这样如果树中间某处的值发生变化,所有父对象都会相应地更新。

希望这些要求有意义

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

4

2 回答 2

2

For something like this, I might go in the other direction. Instead of having the parent object trying to figure out what child objects have changed, I would have a child object notify its parent when a change occurs, which then notifies its parent, and its parent, and so on. Let the information bubble upwards, instead of searching for it downwards. That puts the bulk of the work on the activity that is initiating the change, and makes searches faster since all of the information is pre-cached in the tree without having to hunt for it.

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;
于 2012-08-13T21:30:01.877 回答
2

我还没有遇到过可以执行您想要的操作的现有组件,因此编写自己的组件似乎是合理的。

你的方法会奏效,是我自己用过很多次的方法。您有一个递归数据结构,其中TSomeClass包含更多TSomeClass对象的列表。以任何其他方式遍历此结构将更加复杂。

于 2012-08-13T07:41:21.197 回答