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値を返す関数を呼び出す必要がありますが、関数はクラスの状態の条件に従って動作する必要がありますこれは再帰が期待する場所ですけり込むFSomethingToBeCountedHasTheDataChanged
    • HasTheDataChanged含まれているサブオブジェクトが最新であるためにプロパティがfalseに設定されている場合、その値を返す必要があり、それ以上の処理は実行されません。
    • プロパティがtrueに設定されている場合、HasTheDataChangedデータは最新ではなく、再計算して新しい再計算値を返す必要があります。また、適切なHasTheDataChanged状態を設定して、それ以上の再処理を減らす必要があります。

また、この同様のタイプの伝播はHasTheDataChangedプロパティでも実行する必要があると想定しているため、ツリーの途中で値が変更された場合は、それに応じてすべての親オブジェクトが更新されます。

うまくいけば、これらの要件は理にかなっています

さて、問題の核心に。初めに。私の考えは正しいです。サブオブジェクトのプロパティにアクセスするだけで、正しい値がルートオブジェクトに伝播するため、数千のサブオブジェクトが存在する可能性がある場合に、各サブオブジェクトを検索するために数え切れないほどのコード行を費やす必要がありません。それとも、私がここで車輪の再発明を試みていて、すでに存在し、自分で作成する代わりに使用できるクラスを探しているだけの場合です。最後になりましたが、大事なことではありません。これは物事を行うための最も効率的な方法でしょうか?

4

2 に答える 2

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

私はあなたが望むことをする既存のコンポーネントに出くわしたことがないので、あなた自身を書くことは健全であるように思われます。

あなたの方法はうまくいき、私が何度も使ってきた方法です。さらにオブジェクトのリストを含む再帰的なデータ構造があります。他の方法でこの構造をトラバースすることは、より複雑になります。TSomeClassTSomeClass

于 2012-08-13T07:41:21.197 に答える