迭代TObjectList

时间:2013-01-04 08:45:52

标签: delphi delphi-2010 loops visitor-pattern tobjectlist

我有ObjectList容器,我想添加一个内部 迭代器(Visitor Pattern)实际上我正试图确定 在我的清单中重复..

示例: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 个答案:

答案 0 :(得分:10)

好的,正如我们在评论中发现的那样,我们有两个任务:

  1. 如何查找TObjectList是否已包含项目(因此新项目是重复的)
  2. 如何管理TImageList中的文件图标以减少内存使用量并仅存储唯一图标。
  3. 正如我在评论中提到的,您应该在单独的帖子中询问您的第二个问题,但我建议您添加新文件图标,这取决于新文件mime-type,而不是二进制图标数据。在这里你必须创建文件类型字典,确定文件类型等等。

    TObjectList中的重复内容怎么样? 您可能知道,generic - TObjectListTObjectsList<T>实施。在您的示例中,您可以将TPersonList定义为TObjectList<TPerson>,因此items属性始终返回TPerson个对象实例。

    现在,带有列表的通用任务 - 列表排序。请查看Sort() TObjectList<T>/TList方法。它有2种重载方法。其中一个是默认值,第二个是Comparer作为参数。实际上,第一种方法也使用了比较器 - 默认比较器。 因此,comparer是IComparer<T>接口的实现,它具有唯一的方法 - function Compare(l,r : T):integer;通常在调用Sort()方法之前,在运行时将此排序比较器定义为 anonimous method 。使用你的anonimous方法,你总是知道如何比较两个T类型的对象,然后你可以确定它们比其他对象“更大”,并且应该是列表中的第一个。

    所以在搜索列表中的重复项时遇到的情况相同。但现在你必须确定,2个对象是否相同。

    我们假设您personList : TPersonList包含TPerson个实例。例如,每个人都有姓名,姓氏,出生日期和身份证明。 当然,默认比较器对如何比较2个人一无所知。但你可以提供知道的新比较器。例如,假设2个对象是等于的,如果它们的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构造函数中定义新的比较器。我们应该定义comparsion方法,然后创建comparer对象并将其传递给List contructor。

    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(或其后代)是否包含对象的常用方法。