我有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如何解决这个问题。
提前谢谢......
答案 0 :(得分:10)
好的,正如我们在评论中发现的那样,我们有两个任务:
TObjectList
是否已包含项目(因此新项目是重复的)TImageList
中的文件图标以减少内存使用量并仅存储唯一图标。正如我在评论中提到的,您应该在单独的帖子中询问您的第二个问题,但我建议您添加新文件图标,这取决于新文件mime-type,而不是二进制图标数据。在这里你必须创建文件类型字典,确定文件类型等等。
TObjectList
中的重复内容怎么样?
您可能知道,generic
- TObjectList
已TObjectsList<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
(或其后代)是否包含对象的常用方法。