3

ノード ツリー ( VirtualTreeView )でノードを並べ替える手順があります。FMM4 レポートから抽出されたすべてのメモリ リークは、クラス TMemoryLeakList (これらは並べ替えたいリストです) のオブジェクトに格納され、リストのリストに格納されます。 TGroupedMemoryLeakList と呼ばれ、TMLL と TGMLL の両方が TObjectList を拡張します。昇順と降順の並べ替えを選択できる機能と、4 つの異なるデータ型のいずれかによる並べ替えを選択できる機能を維持したい場合は、8 つの異なる比較方法 (4 つの並べ替えタイプ * 2 つの並べ替え方向) を実装する必要があります。 TMLL リストは TObjectList を拡張しているため、メインの並べ替えメソッドに進みます。主なソート方法は次のようになります

フィールド fSortType および fSortDirection の値は、GUI コンボボックスから取得されます。これら 8 つの一般的な比較関数の 1 つは、次のようになります。残りの 7 つは、このバージョンをコピーして貼り付けたものです。

この膨大な量のコピー ペースト コードをリファクタリングしながら、特定の並べ替えの種類と方向を選択する機能を維持する合理的な方法はありますか?

4

3 に答える 3

5

リファクタリングについての良い質問ですが、おそらくあなたが探している答えは嫌いです。数行のコードや追加のルーチンを追加しても問題はありません。特に後者の場合、ネーミングは読みやすさを積極的に支援します。

私のアドバイスは次のとおりです。デザインはそのままにして、コードを短くします。

function CompareSizeAsc(Item1, Item2: Pointer): Integer;
begin
  Result := TMemoryLeak(Item2).Size - TMemoryLeak(Item1).Size;
end;

function CompareSizeDesc(Item1, Item2: Pointer): Integer;
begin
  Result := TMemoryLeak(Item1).Size - TMemoryLeak(Item2).Size;
end;

function CompareClassNameAsc(Item1, Item2: Pointer): Integer;
begin
  Result := CompareStr(TMemoryLeak(Item1).ClassName,
    TMemoryLeak(Item2).ClassName);
end;

procedure TMemoryLeakList.Sort;
begin
  case FSortDirection of
    sdAsc:
      case FSortType of
        stSize: inherited Sort(CompareSizeAsc);
        stClassName: inherited Sort(CompareClassNameAsc);
        stCallStackSize: inherited Sort(CompareCallStackSizeAsc);
        stId: inherited Sort(CompareIdAsc);
      end;
    sdDesc:
      case FSortType of
        stSize: inherited Sort(CompareSizeDesc);
        stClassName: inherited Sort(CompareClassNameDesc);
        stCallStackSize: inherited Sort(CompareCallStackSizeDesc);
        stId: inherited Sort(CompareIdDesc);
      end;
  end;
end;

これよりもはるかに小さくして、同じレベルの読みやすさを維持することはできません。

もちろん、Arioch 'TheSortが提案するようにルーチンを書き直すこともできます。

procedure TMemoryLeakList.Sort;
const
  Compares: array[TSortDirection, TSortType] of TListSortCompare =
    ((CompareSizeAsc, CompareClassNameAsc, CompareCallStackSizeAsc,
    CompareIdAsc), (CompareSizeDesc, CompareClassNameDesc,
    CompareCallStackSizeDesc, CompareIdDesc));
begin
  inherited Sort(Compares[FSortDirection, FSortType]);
end;

しかし、別の比較ルーチンの必要性をなくすために、QuickSort ルーチンを書き直してはどうでしょうか?

または、TMemoryLeak に所有権を追加することもできます。この場合、単一の比較ルーチン内で使用するために、所有リストとその並べ替え方向および並べ替えタイプへの参照があります。

于 2012-10-01T11:40:41.990 に答える
3

関数ポインタを使用します。

var comparator1, comparator2: function (Item1, Item2: Pointer): Integer;

function sortComplex (Item1, Item2: Pointer): Integer;
begin
  Result := comparator1(Item1, Item2);
  if 0 = Result then   Result := comparator2(Item1, Item2);
end;

次に、GUI要素は次のように動作する必要があります

 case ListSortType.ItemIndex of
    itemBySzie : comparator1 := sortBySizeProcAsc;
....
 end;

 DoNewSort;

PS: ユーザーが最初に GUI 要素をクリックする前であっても、これらのポインターを正しく指定していることを確認してください。

PPS:これをさらに次のように再配置できます

 type t_criteria = (bySize, byName,...);
      t_comparators = array[t_criteria] of array [boolean {Descending?}]
                      of function (Item1, Item2: Pointer): Integer;

 const comparator1table: t_comparators = 
       ( {bySize} ( {false} sortBySizeProcAsc, {true} sortBySizeProcDesc),
         {byName} ( {false} sortByNameProcAsc, ...

次に、その配列定数から作業ポインタを埋めます

于 2012-10-01T10:01:05.950 に答える
0

これが私の解決策です。2 つのプロシージャを完全に書き直すだけでなく、TMemoryLeakList クラスに 2 つの「静的」変数を追加し、同じ名前の以前のインスタンス変数を削除しました。このようにして、Sort 関数からグローバルにアクセスできます。

TMemoryLeakList=class(TObjectList)
class var fSortType      :TMlSortType;
class var fSortDirection :TMLSortDirection;
...
end

procedure TMemoryLeakList.Sort;
begin
  inherited sort(sortBySomethingSomething);
end;

function sortBySomethingSomething(Item1, Item2: Pointer): Integer;
var
 a, b : string;
 ret : Integer;
begin
  ret := 1;
  if(TMemoryLeakList.fSortDirection = sdAsc) then
     ret := -1;
  case TMemoryLeakList.fSortType of stSize:
  begin
    a := IntToStr(TMemoryLeak(Item1).Size);
    b := IntToStr(TmemoryLeak(Item2).Size);
  end;
  end;
  case TMemoryLeakList.fSortType of stClassName:
  begin
    a := TMemoryLeak(Item1).ClassName;
    b := TMemoryLeak(Item2).ClassName;
  end;
  end;
  case TMemoryLeakList.fSortType of stID:
  begin
    a := IntToStr(TMemoryLeak(Item1).ID);
    b := IntToStr(TMemoryLeak(Item2).ID);
  end;
  end;
  case TMemoryLeakList.fSortType of stCallStackSize:
  begin
    a := IntToStr(TMemoryLeak(Item1).CallStack.Count);
    b := IntToStr(TMemoryLeak(Item2).CallStack.Count);
  end;
  end;
  //...jos tu
  if a=b then
    Result:=0
  else if a>b then
    Result:=-1*ret
  else if a<b then
    Result:=1*ret;
end;

fSortType,fSortDirectionでインスタンス境界変数を使用するようにこのソリューションを書き直したいのですTMemoryLeakListが、(から) 継承された並べ替え関数にメンバー関数を渡すことは不可能に思えTObjectListますか?

于 2012-10-01T14:30:10.983 に答える