Выпуск № 8 Списки - продолжаем развивать свою базу данных
Но сначала о печальном. Мне пришло письмо с просьбой поделиться информаций о работе с СОМ - портом в Delphi. В своих архивах я нашел три статьи, но вот обе попытки отослать оказались неудачными. Оба сообщения мне вернулись. Так что прошу автора письма maslen@rambler.ru отозваться или просто скачать небольшой архив: com_port.zip. Лежать там он будет две недели ...
Мы продолжим развивать объект, представляющий собой, по сути дела, базу данных. Предыдущие выпусков можно найти на сайте по адресу http://www.borlpasc.narod.ru/Boris/ogl.htm. Напомню, что исходный код программы состоит из трех частей: модуль uRec.pas, в котором описана структура хранимой единицы информации, модуль BaseObj.pas содержит описание объекта TBaseObj, реализующий нужные действия по сохранению новых данных и выводу их на экран. Третий файл Test.pas выполняет тестирование объекта. Для этого в нем определена переменная типа указатель на объект TBaseObj, программа размещает объект в динамической памяти, добавляет в него одну запись и выводит все хранимые записи на экран. Все три файла в одном архиве можно скачать по адресу http://www.borlpasc.narod.ru/Boris/BaseObj.zip
Добавить следующую запись в конец базы нет можно без проблем. Для этого достаточно добавить строчку кода в программу text.pas
Add(NewOne('Гыр', 'Бор', 123));
Сегодня добавим объекту новое свойство - возможность сохранить базу данных в файл. Но переписывать файл не BaseObj.pas
будем! Но для этого нужно будет добавить новый файл и изменить файл Test.pas.
Итак создаем новый файл с исходным текстом, например, uFileObj.pas. В него поместим такой код:
unit uFileObj; interface uses BaseObj; TYPE PFileDBObj = ^TFileDBobj; TFileDBobj = object(TBaseObj) end; implementation END.Пока еще мы не добавили объекту никаких новых свойств. Просто я хочу показать, как легко в ООП унаследовать свойства объекта. Но тестирующую программу Test.pas теперь сделаем такой:
program Test;
{Программа, тестриующая модуль BaseObj}
uses uFileObj, uRec, CRT;
var
BO: PFileDBObj;
BEGIN
ClrScr;
Bo:=New(PFileDBObj, Init);
if BO <> nil then
with BO^ do
begin
Add(NewOne('Surin','Борис',12));
Add(NewOne('Гыр', 'Бор', 123));
PrintAll;
Dispose(BO, Done);
end;
END.
Мы изменили имя используемого модуля на новый и изменили имя используемого модуля, изменили имя объекта. Пришлось
немного изменить и содержимое оператора New. А программа работает по-прежнему!
Пойдем дальше. В объект TFileDBobj добавим метод: procedure SaveToFile(AFileName: String). Ниже приводится код модуля, в котором описано простейшая реализация метода.
unit uFileObj;
interface
uses BaseObj, uRec;
TYPE
PFileDBObj = ^TFileDBobj;
TFileDBobj = object(TBaseObj)
procedure SaveToFile(AFileName: string);
end;
implementation
procedure TFileDBobj.SaveToFile;
var
f: File of TInfo;
p: POne;
begin
Assign(f, AFileName);
{$I-} Rewrite(f); {$I+}
if IOResult <> 0 then begin
{Файл не удалось открыть (создать)}
WriteLn('Скорее всего имя файла содержит недопустимые символы: ',
AFileName);
Exit;
end;
p:=GetNode;
while p <> nil do begin
Write(f, p^.Info);
p:=p^.Next
end;
Close(f);
end;
END.
Краткое описание метода SaveToFile. В нем объявлена файловая переменная f, которая описывает типизированный файл,
состоящий из записей TInfo, и переменная p типа POne. А далее все почти просто: начиная с первого узла записываем в файл
структуры TInfo с помощью команды Write(f, p^.Info) содержимое записи, и переходим к следующему узлу.Обращу внимание на то, что появился новый метод GetNode. Его необходимо добавить к "прежнему" объекту TBaseObj:
TBaseObj = object
private
Node: POne;
public
constructor Init;
destructor Done; virtual;
procedure Add(ANewOne: POne); virtual;
procedure PrintAll; virtual;
function GetNode: POne;
end;
....
function TBaseObj.GetNode: POne;
begin
GetNode:=Node
end;
Поле Node объявлено в разделе PRIVATE и оно недоступно из наследника объекта TFileDBobj, но объявлять поле Node
доступным опасно. Пользователь может что-то дописать к программе, изменить значение поля и, в лучшем случае, потеряет
возможность обратиться к первым полям базы данных. Выход из, казалось бы, тупиковой ситуации заключается в создании
общедоступного (PUBLIC) метода, который только возвращает значение указателя.
Чтобы загрузить данные из файла необходимо в объект TFileDBobj добавить метод LoadFromFile. Код этого метода дается ниже:
procedure TFileDBobj.LoadFromFile(AFileName: String);
var
f: File of TInfo;
i: TInfo;
begin
Assign(f, AFileName);
{$I-} Reset(f); {$I+}
if IOResult <> 0 then begin
WriteLn('Не могу открыть файл с исходными данными ',AFileName);
Exit;
end;
{Считаем идентификационную запись и сверим ее со "стандартном"}
{$I-} (* Возможны ошибки при чтении информации - вдруг это совсем
другой файл - не "наш" *)
Read(f, i);
if i.Name <> cVersion then begin
WriteLn('Несоответствие версий баз данных:', i.Name);
Close(f); Exit;
{Просто закрываем файл и выходим из процедуры}
end;
{Добавляем в дазу данных}
Add(NewOne(i.Name, i.ForeName, i.Age));
{Считываем все остальные и добавляем. По-видимому,
проверять на правильность считывания не стоит - если
первая запись правильная, то скорее всего и
остальные тоже}
while NOT EOF(f) do begin
Read(f, i);
Add(NewOne(i.Name, i.ForeName, i.Age));
end;
{$I+}
Close(f);
end;
Добавить его в объект, надеюсь, сумеете сами. Если нет, то скачайте архив с исходным кодом всех описанных программ: http://www.borlpasc.narod.ru/Boris/oop008.zip
Удачи. Пишите, ежели что ...
Рассылку поддерживает сайт www.turbopascal.tk
При перепечатке ссылка на сайт обязательна