TObjectList进行迭代



我有ObjectList容器,我想添加一个内部迭代器(访问者模式)实际上我试图确定

示例:http://pastebin.com/pjeWq2uN

这段代码提供了我想要实现的目标的洞察力。

TFindDuplicatesMethod = procedure(s1, s2: string) of object;
TPersonList = class(TObjectList)
public
  procedure Iterate(pMethode: TFindDuplicatesMethod)
end;
procedure TPersonList.Iterate(pMethode: TFindDuplicatesMethod)
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
  pMethode(TMyClass(Items[i]).S1, {But i don't have the second parameter because
                               it comes from outside of PersonList Ex: OpenDialog.Files[i]})
end;
function FindDuplicate(S1, S2: string): Boolean;
begin
  Result := False;
  if S1 = S2 then
  Result := True;
end;
begin
  Files.Iterate(FindDuplicates(S1, S2));
end;

我想知道OOP是如何解决这样的问题的。

好的,正如我们在注释中看到的,我们有两个任务:

  1. 如何查找TObjectList是否已经包含一个项目(因此新项目是重复的)
  2. 如何管理TImageList中的文件图标,以减少内存使用和只存储唯一的图标。

正如我在评论中提到的,你应该在单独的线程中询问你的第二个问题,但我建议你根据新的文件mime类型添加新的文件图标,而不是二进制图标数据。这里你需要创建文件类型字典,确定文件类型等等。

TObjectList中重复的是什么?你可能知道,TObjectList - TObjectsList<T>generic实现。在你的例子中,你可以将TPersonList定义为TObjectList<TPerson>,所以items属性总是返回TPerson对象的实例。

现在,具有列表的通用任务-列表排序。看看TObjectList<T>/TListSort()方法。它有2个重载方法。其中一个是默认的,第二个以Comparer作为参数。实际上,第一个方法也使用了一个比较器——默认比较器。所以comparer是IComparer<T>接口的实现,它只有一个方法——function Compare(l,r : T):integer;通常,在调用Sort()方法之前,在运行时将这个排序比较器定义为匿名方法。使用匿名方法,您总是知道如何比较两个T类型的对象,然后您可以确定其中哪个比另一个"更大",并且应该是列表中的第一个。

所以你在list中搜索重复项时遇到的情况是一样的。但现在你必须确定,两个对象是否相等。

让我们假设您有personList : TPersonList,其中包含TPerson实例。例如,每个人都有姓名、出生日期和身份证件。当然,默认比较者不知道如何比较两个人。但是你可以提供新的比较者。例如,假设两个对象相等,如果它们的id相等;

    TPerson = class(TObject)
      strict private
        FName : string;
        FSurname : string;
        FDateOfBirth : TDateTime;
        FId : string;   {passport number or something else}
      public
        constructor Create(aID : string; aDoB : TDateTime);
        property Name : string read FName write FName;
        property Surname : string read FSurname write FSurname;
        property DateOfBirth : TDateTime read FDateOfBirth;
        property ID : string read FId;
    end;

    TPersonList = class(TObjectList<TPerson>)
      public
        constructor Create();
    end;

TPerson构造函数通常为:

constructor TPerson.Create(aID: string; aDoB: TDateTime);
begin
    inherited Create();
    FID := aId;
    FDateOfBirth := aDoB;
end;

现在我们必须写TPersonList构造函数。可以看到,TObejctList构造函数几乎没有重载。其中一个参数为Comparer。将aComparer字段保存为FComparer字段。现在,看看Contains方法。它查找列表是否已经包含对象。它使用IndexOf方法。因此,如果返回索引= 0,则list包含我们的对象。

现在我们的任务是在TPersonList构造函数中定义新的比较器。首先定义比较方法,然后创建comparer对象,并将其传递给List构造函数。

constructor TPersonList.Create();
var comparer : IComparer<TPerson>;
    comparison : TComparison<TPerson>;
begin
    comparison := function(const l,r : TPerson):integer
                  begin
                    if l.ID = r.id then exit(0)
                    else if l.ID > r.ID then exit(-1)
                    else exit(1);
                  end;
    comparer := TComparer<TPerson>.Construct(comparison);
    inherited Create(comparer);
end;

为了测试我们的代码,让我们添加一些人到列表中。

procedure TForm2.FormCreate(Sender: TObject);
var persons : TPersonList;
    function AddPerson(id : string; date : TDateTime):boolean;
    var p : TPerson;
    begin
        p := TPerson.Create(id, date);
        result := not persons.Contains(p);
        if result then
            persons.Add(p)
        else begin
            ShowMessage('list already contains person with id = ' + id);
            p.Free();
        end;
    end;
begin
    persons := TPersonList.Create();
    try
        AddPerson('1', StrToDate('01.01.2000'));
        AddPerson('2', StrToDate('01.01.2000'));
        AddPerson('3', StrToDate('01.01.2000'));
        AddPerson('2', StrToDate('01.01.2000')); // we will get message here.
    finally
        persons.Free();
    end;
end;

因此,这是如何确定TList(或其后代)是否包含对象的常用方法。

最新更新