Он не будет дочерним классом TList. Конечно, в нем будут содержаться те же методы, но их реализация будет основана на делегировании к методам с теми же именами внутреннего класса TList.
Класс TtdObjectList имеет один новый очень важный атрибут - владение данными. Это класс будет функционировать либо точно так же, как TList, т.е. при уничтожении его элементы не будут освобождаться (он не владеет данными), либо будет иметь полный контроль над своими элементами и при необходимости будет их удалять (он владеет данными). Установка атрибута владения данными выполняется при создании экземпляра класса TtdObjectList, и после этого уже не будет возможности изменить тип владения данными.
Кроме того, класс будет обеспечивать безопасность к типам (type safety). При создании экземпляра класса, необходимо указывать какой тип (или класс) объектов будет в нем храниться. Во время добавления или вставки нового элемента специальный метод будет проверять соответствие типа нового объекта объявленному типу элементов списка.
Интерфейс класса TtdObjectList напоминает интерфейс класса TList. В нем не реализован метод Pack, поскольку в список будут добавляться только объекты, не равные nil. Подробное описание метода Sort будет приведено в главе 5.
Листинг 2.10. Объявление класса TtdObjectList
TtdObjectList = class private
FClass : TClass;
FDataOwner : boolean;
FList : TList;
FName : TtdNameString;
protected
function olGetCapacity : integer;
function olGetCount : integer;
function olGetItem(aIndex : integer): TObject;
procedure olSetCapacity(aCapacity : integer);
procedure olSetCount(aCount : integer);
procedure olSetItem(aIndex : integer; aItem : TObject);
procedure olError(aErrorCode : integer; const aMethodName : TtdNameString; aIndex : integer);
public
constructor Create(aClass : TClass;
aDataOwner : boolean);
destructor Destroy; override;
function Add(aItem : TObject): integer;
procedure Clear;
procedure Delete(aIndex : integer);
procedure Exchange(aIndex1, aIndex2 : integer);
function First : TObject;
function IndexOf(aItem : TObject): integer;
procedure Insert(aIndex : integer; aItem : TObject);
function Last : TObject;
procedure Move(aCurIndex, aNewIndex : integer);
function Remove(aItem : TObject): integer;
procedure Sort(aCompare : TtdCompareFunc);
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. Намного эффективнее очищать список после освобождения памяти, занимаемой его элементами.)
Читать дальше