Здесь мы рассмотрим использование ранее созданных объектов и создадим модуль,
управляющий "поведением" этих объектов.
Идею инкапсуляции полей и алгоритмов можно применить не только к графическим объектам, но и ко всей программе в целом. Ничто не мешает нам создать объект-программу и "научить" его трем основным действиям: инициации (Init), выполнению основной работы (Run) и завершению (Done). На этапе инициации экран переводится в графический режим работы, создаются и отображаются графические объекты (100 экземпляров TPoint и по одному экземпляру TLine, TCircle, TRect). На этапе Run осуществляется сканирование клавиатуры и перемещение графических объектов. Наконец, на этапе Done экран переводится в текстовый режим и завершается работа всей программы.
Назовем объект-программу именем TGraphApp и разместим его в модуле GraphApp:
Unit GraphApp;
Interface
Type
TGraphApp = Object
Procedure Init;
Procedure Run;
Destructor Done;
End;
Implementation
. . . . . .
End.
В этом случае основная программа будет предельно простой:
Program Graph_Objects; Uses GraphApp; Var App: TGraphApp; Begin App.Init; App.Run; App.Done; End.
В ней мы создаем единственный экземпляр App объекта-программы TGraphApp и обращаемся к трем его методам.
Создание экземпляра объекта не отличается от создания экземпляра переменной любого
другого типа. Просто в разделе описания переменных мы указываем имя переменной и
ее тип:
Var
App: TGraphApp; .
Получив это указание, компилятор зарезервирует нужный объем памяти для размещения
всех полей объекта TGraphApp. Чтобы обратиться к тому или иному объектному
методу или полю, используется составное имя, причем первым указывается не имя объектного
типа, а имя соответствующей переменной:
App.Init;
App.Run;
App.Done;
Переменные объектного типа могут быть статическими или динамическими, то есть
располагаться в сегменте данных (статические) или в "куче" (динамические). В последнем
случае мы могли бы использовать такую программу:
Program Graph_Objects; Uses GraphApp; Type PGraphApp = ^TGraphApp; Var App:PGraphApp; Begin App:=New(PGraphApp); App^.Init; App^.Run; App^.Done; Dispose(App); End.
Для инициации динамической переменной App используется вызов функции New. В этом случае первым параметром указывается имя типа инициируемой переменной, а вторым осуществляется вызов метода - конструктора, который нужен для настройки таблицы виртуальных методов.
Приведем вариант модуля GraphApp для учебной программы:
Unit GraphApp; Interface Uses GraphObj; Const NPoints = 100; {Количество точек} Type TGraphApp = Object Points: Array [1..NPoints] Of TPoint; {Массив точек} Line: TLine; {Линия} Rect: TRect; {Прямоугольник} Circ: TCircle; {Окружность} ActiveObj: Integer; {Активный объект} Procedure Init; Procedure Run; Destructor Done; Procedure ShowAll; Procedure MoveActiveObj (dX,dY:Integer); End; Implementation Uses Graph,CRT; Procedure TGraphApp.Init; {Инициализирует графический режим работы экрана. Создает и} {отображает NPoints экземпляров объекта TPoint, а также } {экземпляры объектов TLine,TCircle, TRect. } Var D,R,Err,k: Integer; Begin D:=Detect; InitGraph(D,R,'D:\BP\BGI'); Err:=GraphResult; If Err<>0 Then Begin GraphErrorMsg(Err); Halt; End; For k:=1 To NPoints Do Points[k].Init(Random(GetMaxX),Random(GetMaxY),Random(15)+1); Line.Init(GetMaxX div 3,GetMaxY div 3,2*GetMaxX div 3, 2*GetMaxY div 3,LightRed); Circ.Init(GetMaxX div 2,GetMaxY div 2,GetMaxY div 5,White); Rect.Init(2*GetMaxX div 5,2*GetMaxY div 5,3*GetMaxX div 5, 3*GetMaxY div 5,Yellow); ShowAll; {Показать графические объекты} ActiveObj:=1; {Первым перемещаем прямоугольник} End; Procedure TGraphApp.Run; {Выбор и перемещение объекта по экрану} Var Stop: Boolean; {Признак нажатия ESC} Const D=5; {Шаг смещения фигур} Begin Stop:=False; Repeat {Цикл опроса клавиатуры} Case ReadKey Of {Читаем код нажатой клавиши} #27: Stop:=True; {Нажата клавиша ESC} #9: Begin {Нажата клавиша TAB} Inc (ActiveObj); If ActiveObj>3 Then ActiveObj:=1; End; #0: Case ReadKey Of #71: MoveActiveObj(-D,-D); {Влево и вверх} #72: MoveActiveObj(0,-D); {Вверх} #73: MoveActiveObj( D,-D); {Вправо и вверх} #75: MoveActiveObj(-D,0); {Влево} #77: MoveActiveObj( D,0); {Вправо} #79: MoveActiveObj(-D,D); {Влево и вниз} #80: MoveActiveObj(0, D); {Вниз} #81: MoveActiveObj( D, D); {Вправо и вниз} End; End; ShowAll; Until Stop; End; Destructor TGraphApp.Done; Begin CloseGraph; End; Procedure TGraphApp.ShowAll; {Показ всех объектов} Var k:Integer; Begin For k:=1 To NPoints Do Points[k].Show; Line.Show; Rect.Show; Circ.Show; End; Procedure TGraphApp.MoveActiveObj {Перемещение активного объекта}; Begin Case ActiveObj Of 1: Rect.MoveTo(dX,dY); 2: Circ.MoveTo(dX,dY); 3: Line.MoveTo(dX,dY); End; End; End.
В реализации объекта TGraphApp используется деструктор Done.
Следует иметь в виду, что в отличие от конструктора, осуществляющего настройку ТВМ,
деструктор не связан с какими-то специфичными действиями. Для компилятора слова
Destructor и Procedure - синонимы. Введение в ООП деструкторов носит,
в основном, стилистическую направленность - просто процедуру, разрушающую экземпляр
объекта, принято называть деструктором. В реальной практике ООП с деструкторами
обычно связывают процедуры, которые не только прекращают работу с объектом, но и
освобождают выделенную для него динамическую память.
Со следующего шага начинается приложение, содержащее краткие сведения по
некоторым ранее изложенным темам.