пятница, 12 декабря 2008 г.

Теория и практика объектно-ориентированного программирования в Delphi

Сессия приближается как всегда стремительно. Решил заняться программированием на Delphi. Поскольку раньше объектно-ориентированным программированием (ООП) в Pascal не занимался, пришлось немного напрягать мозги.

Итак, цель была поставлена следующая:
Разработать диалоговую программу как Windows-приложение для работы с объектами заданного типа. Программа должна содержать меню и выполнять следующие операции: создание объектов двух заданных классов и сохранение их в списке TList, просмотр и редактирование объектов, сохранение объектов в потоке TList и загрузка их из потока.

Ниже приведён кратенький рассказик о сохранении и чтении информации в этой программе.

1. Основная форма приложения Form1. На ней были размещены компонент TMainMenu, два списка TListBox для просмотра объектов (для каждого типа объектов свой список), две кнопки TButton сортировки списка TList по разным критериям, а также компоненты стандартных диалогов TOpenDialog и TSaveDialog.
2. Создан модуль Unit2, содержащий код двух пользовательских классов и один абстрактный класс.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Contnrs;
type
TOrganization = class(TComponent)
Private
Name: String;
Year_founded: Integer;
Capital: Real;
Protected
Public
Constructor Create(Collection: TComponent); override;
Procedure Show(); virtual; abstract;
Published
Property MyName: String read Name write Name;
Property MyYear_founded: Integer read Year_founded write Year_founded;
Property MyCapital: Real read Capital write Capital;
end;

TInsurance = class(TOrganization)
Private
Clients: Integer;
Protected
Public
Constructor Create(nname: string; ncapital: real; nyear: integer; nclients: Integer);
Procedure Show(); override;
Published
Property MyClients: Integer read Clients write Clients;
end;

TShipbuilding = class(TOrganization)
Private
Vessel: Integer;
Protected
Public
Constructor Create(nname: string; ncapital: real; nyear: integer; nvessel: Integer);
Procedure Show(); override;
Published
Property MyVessel: Integer read Vessel write Vessel;
end;

implementation
uses Unit5, Unit6, Unit7;

Constructor TOrganization.Create;
begin
end;

Constructor TInsurance.Create(nname: string; ncapital: Real; nyear: integer; nclients: Integer);
begin
Name:=nname;
Year_founded:=nyear;
Capital:=ncapital;
Clients:=nclients;
end;

Constructor TShipbuilding.Create(nname: string; ncapital: Real; nyear: integer; nvessel: Integer);
begin
Name:=nname;
Year_founded:=nyear;
Capital:=ncapital;
Vessel:=nvessel;
end;

Procedure TInsurance.Show();
begin
Form5.Edit1.Text:=Name;
Form5.Edit2.Text:=inttostr(round(Capital));
Form5.Edit3.Text:=inttostr(Year_founded);
Form5.Edit4.Text:=inttostr(Clients);
Form7.Visible:=True;
Form5.Visible:=True;
end;

Procedure TShipbuilding.Show();
begin
Form6.Edit1.Text:=Name;
Form6.Edit2.Text:=inttostr(round(Capital));
Form6.Edit3.Text:=inttostr(Year_founded);
Form6.Edit4.Text:=inttostr(Vessel);
Form7.Visible:=True;
Form6.Visible:=True;
end;

initialization
RegisterClasses([TComponent, TOrganization, TInsurance, TShipbuilding]);
end.
Важно не упустить следующие вещи:
  1. Абстрактный класс должен быть наследником TComponent.
  2. Все свойства (Property) класса, которые будет необходимо сохранить в файл, нужно объявлять в Published части.
  3. Все классы нужно зарегистрировать с помощью RegisterClasses.
3. Формы для ввода новых элементов. Form3 и Form4 создаются аналогично друг другу, различие только в пользовательском классе.
Код для кнопок выглядит следующим образом:
procedure TForm3.Button1Click(Sender: TObject);
Var
NewInsurance: TInsurance;
begin
if Edit4.Text='' then Edit4.SetFocus;
if Edit3.Text='' then Edit3.SetFocus;
if Edit2.Text='' then Edit2.SetFocus;
if Edit1.Text='' then Edit1.SetFocus;

if ((Edit1.Text<>'') and(Edit2.Text<>'') and (Edit3.Text<>'') and (Edit4.Text<>'')) then
Begin
NewInsurance:=TInsurance.Create(Edit1.Text,strtofloat(Edit2.Text), strtoint(Edit3.Text), strtoint(Edit4.Text));
MyArray.Add(NewInsurance);
Form1.ListBox1.Items.Add(NewInsurance.MyName);
Modified:=true;
ModalResult:= mrOK;
End;
end;

procedure TForm3.Button2Click(Sender: TObject);
begin
Form3.Close;
end;
4. Итак, самое интересное. Функция записи в файл реализована на TStream с использованием функции WriteComponent. Вызывается из соответствующего пункта меню на Form1.
procedure TForm1.N2Click(Sender: TObject);
var
FileStream: TStream;
I: Integer;
MySave: TOrganization;
begin
if not Modified then exit;
SaveDialog1:=TSaveDialog.Create(self);
SaveDialog1.Filter:='dat';
SaveDialog1.DefaultExt:='dat';
if SaveDialog1.Execute then
Begin
FileStream:=TFileStream.Create(SaveDialog1.FileName, fmCreate);
for I:=0 to MyArray.Count-1 do
Begin
MySave:=TOrganization(MyArray.Items[I]);
FileStream.WriteComponent(MySave as TOrganization);
End;
FileStream.Free;
end;
Modified:=false;
End;
5. Функция Чтения из файла. Здесь на нас трудится функция ReadComponent.
procedure TForm1.N3Click(Sender: TObject);
var
FileStream: TStream;
Temp: TComponent;
MyLoad: TOrganization;
begin
OpenDialog1:=TOpenDialog.Create(self);
OpenDialog1.Filter:='dat';
OpenDialog1.DefaultExt:='dat';
if OpenDialog1.Execute then
Begin
//Очистка
MyArray.Clear;
ListBox1.Clear;
ListBox2.Clear;
//Сама загрузка
FileStream:=TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
while FileStream.Position
begin
MyLoad:=TOrganization.create(self);
MyLoad:=TOrganization(FileStream.ReadComponent(nil));
MyArray.Add(MyLoad);
if MyLoad is TInsurance then ListBox1.Items.add(MyLoad.MyName);
if MyLoad is TShipbuilding then ListBox2.Items.Add(MyLoad.MyName);
end;
Modified:=false;
FileStream.Free;
End;
end;
Прошу прощения, что код программы не полон и отсутствуют толковые комментарии. Возможно подобная инструкция кому-нибудь пригодится :)

Комментариев нет:

Отправить комментарий