В современном программировании на Delphi часто возникает необходимость Sorting объектов в списке. Одна из распространенных проблем, с которой сталкиваются разработчики, - это дублирование кода в методах сортировки. В этой статье мы рассмотрим, как можно оптимизировать код, уменьшив дублирование в методе сортировки с восемью компараторами в Delphi.
Представьте, что у вас есть список утечек памяти, которые необходимо отсортировать. Каждый объект в списке имеет четыре атрибута: размер, имя класса, размер стека вызовов и идентификатор. Вам нужноAbility to choose between ascending and descending sort order and choose between sorting by one of four different data types. To do this, вы должны реализовать восемь различных методов сравнения (четыре типа сортировки * два направления сортировки).
Вот пример кода, который демонстрирует проблему дублирования кода:
type
TMemoryLeak = class
private
FSize: Integer;
FClassName: string;
FCallStackSize: Integer;
FID: Integer;
public
property Size: Integer read FSize;
property ClassName: string read FClassName;
property CallStackSize: Integer read FCallStackSize;
property ID: Integer read FID;
end;
TMemoryLeakList = class(TObjectList<TMemoryLeak>)
private
FSortType: TSortType;
FSortDirection: TSortDirection;
public
procedure Sort;
end;
procedure TMemoryLeakList.Sort;
begin
case FSortDirection of
sdAsc:
case FSortType of
stSize: inherited Sort(TMemoryLeak.SortBySizeAsc);
stClassName: inherited Sort(TMemoryLeak.SortByClassNameAsc);
stCallStackSize: inherited Sort(TMemoryLeak.SortByCallStackSizeAsc);
stID: inherited Sort(TMemoryLeak.SortByIDAsc);
end;
sdDesc:
case FSortType of
stSize: inherited Sort(TMemoryLeak.SortBySizeDesc);
stClassName: inherited Sort(TMemoryLeak.SortByClassNameDesc);
stCallStackSize: inherited Sort(TMemoryLeak.SortByCallStackSizeDesc);
stID: inherited Sort(TMemoryLeak.SortByIDDesc);
end;
end;
end;
function TMemoryLeak.SortBySizeAsc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item2.Size - Item1.Size;
end;
function TMemoryLeak.SortBySizeDesc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item1.Size - Item2.Size;
end;
function TMemoryLeak.SortByClassNameAsc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := CompareStr(Item1.ClassName, Item2.ClassName);
end;
function TMemoryLeak.SortByClassNameDesc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := CompareStr(Item2.ClassName, Item1.ClassName);
end;
function TMemoryLeak.SortByCallStackSizeAsc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item2.CallStackSize - Item1.CallStackSize;
end;
function TMemoryLeak.SortByCallStackSizeDesc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item1.CallStackSize - Item2.CallStackSize;
end;
function TMemoryLeak.SortByIDAsc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item2.ID - Item1.ID;
end;
function TMemoryLeak.SortByIDDesc(Item1, Item2: TMemoryLeak): Integer;
begin
Result := Item1.ID - Item2.ID;
end;
Как видите, в этом коде мы имеем восемь различных методов сравнения, которые фактически делают одно и то же, но с разными атрибутами объектов TMemoryLeak. Это приводит к дублированию кода и затрудняет поддержание и сопровождение кода.
Одним из решений этой проблемы может быть использование функции-компаратора, которая принимает в качестве параметра атрибут, по которому нужно сравнить объекты. Вот пример кода, который реализует это решение:
type
TMemoryLeak = class
private
FSize: Integer;
FClassName: string;
FCallStackSize: Integer;
FID: Integer;
public
property Size: Integer read FSize;
property ClassName: string read FClassName;
property CallStackSize: Integer read FCallStackSize;
property ID: Integer read FID;
end;
TMemoryLeakList = class(TObjectList<TMemoryLeak>)
private
FSortType: TSortType;
FSortDirection: TSortDirection;
FSortComparer: TMemoryLeakComparer;
public
procedure Sort;
end;
type
TMemoryLeakComparer = function(Item1, Item2: TMemoryLeak): Integer;
function CompareAscending<T>(A, B: T): Integer;
begin
Result := A - B;
end;
function CompareDescending<T>(A, B: T): Integer;
begin
Result := B - A;
end;
procedure TMemoryLeakList.Sort;
begin
case FSortDirection of
sdAsc:
FSortComparer := CompareAscending<TMemoryLeak>;
sdDesc:
FSortComparer := CompareDescending<TMemoryLeak>;
end;
inherited Sort(FSortComparer);
end;
function TMemoryLeakComparer(SortType: TSortType; Item1, Item2: TMemoryLeak): Integer;
begin
case SortType of
stSize: Result := Item1.Size - Item2.Size;
stClassName: Result := CompareStr(Item1.ClassName, Item2.ClassName);
stCallStackSize: Result := Item1.CallStackSize - Item2.CallStackSize;
stID: Result := Item1.ID - Item2.ID;
end;
end;
В этом примере мы создаем функцию-компаратор TMemoryLeakComparer, которая принимает в качестве параметра атрибут, по которому нужно сравнить объекты. В методе Sort мы устанавливаем значение FSortComparer в зависимости от направления сортировки, а затем вызываем метод Sort базового класса TObjectList с передачей функции-компаратора в качестве параметра.
Таким образом, мы можем существенно уменьшить дублирование кода в методе сортировки и сделать код более чистым и легко поддерживаемым.
В программировании на Delphi необходимо оптимизировать код сортировки объектов в списке, уменьшив дублирование в методе сортировки с восемью компараторами.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.