Создание коллекций
Для создания коллекции следует прежде всего определить тип тех данных, которые будут в ней храниться. Например, Вам необходимо создать электронный каталог Вашей личной библиотеки. В этом случае для каждой указанной в каталоге книги можно выделить пять полей данных: автор, название, издательство, год издания и количество страниц. Создадим новый объект TBook следующего вида:
Uses Objects;
type
PBook = TBook;
TBook = object (TObject)
Autor: PSbring; {Автор}
Title: PString; {Название}
PubHouse: PString; {Издательство}
Year: Word; {Год издания}
Pages: Word; {Количество страниц}
Constructor Init(A,T,PH: String; Y,P: Word);
Destructor Done; Virtual;
end ;
Мы включили' в объект поля и два основных метода работы с ними: конструктор Init используется для размещения в динамической памяти очередной записи каталога, деструктор Done удаляет записи из кучи. Заметим, что в объекте задаются не сами текстовые строки, а указатели на них (тип PString в Turbo Vision описан как указатель на тип String). Такое размещение данных как правило дает значительную экономию памяти. Например:
Constructor TBook.Init(А,Т,РН: String; Y,P: Word);
begin
Autor := NewStr(A);
Title := NewStr(T);
PubHouse := NewStr(PH);
Year := Y;
Pages := P
end; {TBook.Init}
Используемые в конструкторе функции NewStr размещают в динамической памяти текстовую строку, выделяя под нее минимально необходимую память, что значительно выгоднее по сравнению с типичным описанием текстовых полей вида
type
TBook = object (TObject)
Autor, Title, PubHouse: String;
.....
end;
Для освобождения динамической памяти в деструкторе Done используется процедура DisposeStr:
Destructor TBook.Done;
begin
DisposeStr(Autor);
DisposeStr(Title);
DisposeStr (PubHouse)
end; {TBook.Init}
После того как тем или иным способом определены типы данных, создание коллекции не вызывает проблем. Например:
var
BookList: PCollection;
begin
BookList := New(PCollection, Init(50,10));
with BookList do
begin
Insert(New(PBook, Init('Джордейн Р.',
'Справочник программиста персональных компьютеров'+
' типа IBM PC, XT и AT','Финансы и статистика',
1991,544)));
Insert(New(PBook, Init('Шелдон',
'Язык Си для профессионалов','И.В.К.-СОФТ',1991,383))); Insert(New(PBook, Init('Скэнлон Л.',
'Персональные ЭВМ IBM PC и XT. '+
'Программирование на языке ассемблера',
'Радио и связь',1991,336)));
Insert(New(PBook,
Init('Йенсен К., Вирт Н.',
'Паскаль. Руководство для пользователя '+
'и описание языка','Финансы и Статистика',1982,151)));
end ;
.....
Dispose(BookList, Done);
end;
Для создания коллекции мы обратились к методу TCollection.Init, указав ему начальную длину коллекции (50 элементов) и шаг наращивания (10 элементов). Руководствуясь этими указаниями, Turbo Vision зарезервирует в динамической памяти место для размещения 50 указателей. Если в ходе наполнения коллекции ее длина превысит начальную, Turbo Vision будет наращивать коллекцию порциями, каждая из которых достаточна для размещения 10 указателей.
Смысл параметров, передаваемых методу TCollection.Init, станет понятнее, если рассмотреть механизм создания и обновления коллекции. Вначале в куче резервируется участок памяти, достаточный для размещения массива из N0 указателей (N0 - начальный размер коллекции). Если в ходе наполнения коллекции ее длина превысит N0 элементов, резервируется новый участок памяти, достаточный для размещения массива из NO + DN указателей (DN - шаг наращивания коллекции), затем старый массив переносится на новое место, а память, выделенная под его размещение, возвращается в кучу. Таким образом, чем больше начальная длина коллекции и шаг ее наращивания, тем меньше суммарные потери времени на расширение коллекции, но и тем больше могут стать потери памяти, есди реальная длина коллекции окажется значительно меньше NO + k*DN (k = О, 1, 2,...).
Операторы Insert размещают в динамической памяти элементы коллекции. В реальной программе наполнение коллекции будет, судя по всему, осуществляться каким-то иным способом, чем простое программирование обращений к методу Insert (см., например, программу Notebook из гл.15). Для нас сейчас важно другое: мы нигде не говорили коллекции, какого типа объекты она будет хранить; для обеспечения нужных действий по размещению в памяти очередного элемента мы просто обращаемся к соответствующему методу Init, а уж он делает остальное - ведь он «знает» как это следует сделать.
Отметим, что обращение
Dispose(BookList, Done);
вызывает автоматическое обращение к методу TBook.Done перед уничтожением каждого элемента коллекции, после чего уничтожается экземпляр TCollection. Это стало возможным потому, что объект TBooh объявлен нами как потомок от TObject. Если бы мы его объявили независимым объектом
type
TBook = object
.....
end;
мы должны были бы сами позаботиться об освобождении кучи, а обращение
Dispose(BookList, Done);
привело бы к «зависанию» программы.