property Capacity : integer read olGetCapacity write olSetCapacity;
property Count : integer read olGetCount write olSetCount;
property DataOwner : boolean read FDataOwner;
property Items[Index : integer] : TObject read olGetItem write olSetItem; default;
property List : TList read FList;
property Name : TtdNameString read FName write FName;
end;
Целый ряд методов класса TtdObjectLiet является простыми интерфейсами для вызова соответствующих методов внутреннего класса FList. Например, вот реализация метода TtdObjectList.First:
Листинг 2.11. Метод TtdObjectList.First
function TtdObjectList.First : TObject;
begin
Result := TObject(FList.First);
end;
В тех методах, которые в качестве входного параметра принимают индекс, до вызова соответствующего метода класса FList индекс проверяется на предмет попадания в допустимый диапазон. Строго говоря, эта процедура не обязательна, поскольку сам класс FList будет производить аналогичную проверку, но в случае возникновения ошибки методы класса TtdObjectList позволят получить больший объем информации. Вот один из примеров - метод Move:
Листинг 2.12. Метод TtdObjectList.Move
procedure TtdObjectList.Move(aCurIndex, aNewIndex : integer);
begin
{проверяем индексы сами, а не перекладываем эту обязанность на список}
if (aCurIndex < 0) or (aCurIndex >= FList.Count) then
olError(tdeIndexOutOfBounds, 'Move', aCurIndex);
if (aNewIndex < 0) or (aNewIndex >= FList.Count) then
olError(tdeIndexOutOfBounds, 'Move', aNewIndex);
{переместить элементы}
FList.Move(aCurIndex, aNewIndex);
end;
Конструктор класса в качестве входных параметров принимает тип объектов, которые будут храниться в списке (чем обеспечивается безопасность класса к типам), и атрибут владения данными. После этого создается внутренний экземпляр класса FList. Деструктор очищает список и освобождает память, занимаемую списком.
Листинг 2.13. Конструктор и деструктор класса TtdObjectList
constructor TtdObjectList.Create(aClass : TClass; aDataOwner : boolean);
begin
inherited Create;
{сохранить класс и флаг владения данными}
FClass := aClass;
FDataOwner := aDataOwner;
{создать внутренний список}
FList := TList.Create;
end;
destructor TtdObjectList.Destroy;
begin
{если список содержит элементы, очистить их и уничтожить список}
if (FList <> nil) then begin
Clear;
FList.Destroy;
end;
inherited Destroy;
end;
Если вы не уверены, каким образом передавать значение параметра aClass, приведем пример с использованием класса TButton:
var
MyList : TtdObjectList;
begin
• • •
MyList := TtdObjectList.Create(TButton, false);
Первым реальным отличием нового списка от стандартного класса TList является метод Clear. Он предназначен для проверки того, владеет ли список данными. В случае положительного результата, перед уничтожением списка все его элементы будут удалены. (Обратите внимание, что здесь для удаления каждого отдельного элемента не используется метод Delete класса FList. Намного эффективнее очищать список после освобождения памяти, занимаемой его элементами.)
Листинг 2.14. Метод TtdObjectList.Clear
procedure TtdObjectList.Clear;
var
i : integer;
begin
{если данные принадлежат списку, перед очисткой списка освобождаем память, занимаемую элементами}
if DataOwner then
for i := 0 to pred(FList.Count) do
TObject(FList[i]).Free;
FList.Clear;
end;
Методы Delete и Remove перед удалением выполняют один и тот же тип проверки, и если список владеет данными, объект освобождается, после чего удаляется и список. Обратите внимание, что в методе Remove используется не вызов метода FList.Remove, а полная реализация метода. Такой подход называется 'кодированием на основе главных принципов'. Он обеспечивает более глубокий контроль и дает более высокую эффективность.
Листинг 2.15. Удаление элемента из списка TtdObjectList
procedure TtdObjectList.Delete(aIndex : integer);
begin
{проверяем индексы сами, а не перекладываем эту обязанность на список}
if (aIndex < 0) or (aIndex >= FList.Count) then