TEllipseSprite=class(TTracedSprite)
private
// Поле
// Хранит цвет эллипса
FColor:Graphics.TColor;
protected
// Методы
// Изображает эллипс
procedure PaintPicture;override;
// Устанавливает цвет эллипса
procedure SetColor(const aColor:Graphics.TColor);
public
// Свойство
// Возвращает и устанавливает цвет эллипса
property Color:Graphics.TColor read FColor write SetColor;
// Метод
// Выполняет инициализирующие действия сразу после создания спрайта
procedure AfterConstruction;override;
end;
Вспомним правила описания в Delphi в контексте приведенного выше интерфейса модуля uSprite. С этой целью рассмотрим фрагмент начала модуля
uses Controls,Graphics,Classes,Types;
type
// Предварительное объявление класса TSprite
TSprite=class;
// Тип переменных, содержащих ссылки на классы типа TSprite
TSpriteClass=class of TSprite;
// Список спрайтов
TSpriteList=class
// Описание членов класса
…
end;
· Директива uses означает, что в коде настоящего модуля используются типы, переменные, процедуры, функции или константы (короче – имена), описанные в интерфейсах модулей Controls, Graphics, Classes, Types. Все перечисленные модули принадлежат в данном случае библиотеке среды Delphi.
· Служебное слово type означает, что ниже следует описание типов. Тип – это формат переменных. Существуют стандартные типы такие как , , и другие. Их формат задан средой. Другие типы, которые оказываются необходимыми в конкретном приложении или модуле, требуют специального описания.
· Краткое описание TSprite=class; типа TSprite означает, что класс TSprite будет описан ниже, но упоминание о нем необходимо уже здесь. Дело в том, что описанный ниже класс TSpriteList использует в своем описании TSprite. В то же время полное описание класса TSprite в свою очередь содержит ссылку на класс TSpriteList. Эта взаимозависимость описаний двух классов не позволяет предпочесть в порядке описания один класс другому. Выход – дать краткое (пустое) описание одного из классов перед полным описанием другого.
· Тип TSpriteClass=class of TSprite описывает переменные, которые содержат в себе ссылки на таблицы виртуальных методов класса TSprite и его наследников. Такие переменные могут быть использованы, например, при создании экземпляра объекта, о котором во время программирования известно лишь то, что он принадлежит к семейству спрайтов, то есть является наследником класса TSprite. Так одним из параметров метода AddSprite(const aSpriteClass: TSpriteClass; const SpriteRect: Types.TRect) класса TSpriteList является переменная типа TSpriteClass, указывающая, экземпляр какого класса спрайтов следует добавить в список.
Строка TSpriteList=class открывает описание класса, которое содержит в себе поля, свойства и методы класса TSpriteList вплоть до служебного слова end, завершающего перечисление членов класса. Все поля объекта инициализируются при явном вызове конструктора в коде приложения. По умолчанию, если в теле конструктора не указаны другие значения, все поля будут инициализированы нулями.
Каждый член класса TSpriteList имеет определенный уровень доступа. Так в описании класса TSpriteList имеется две секции, выделенные модификаторами доступа private и public.
Рассмотрим фрагмент кода, описывающий класс TSpriteList:
TSpriteList=class
private
// Поля
// Хранит канву ("контекст устройства"),используемую для отображения спрайтов списка
FCanvas:Controls.TControlCanvas;
…
// Метод
// Возвращает спрайт списка под номером aZ
function GetSprite(aZ:integer):TSprite;
public
// Свойства
// Возвращает ссылку на канву, с которой связаны спрайты списка
property Canvas:Controls.TControlCanvas read FCanvas;
…
// Возвращает спрайт из списка как элемент массива
property Sprites[aZ:integer]:TSprite read GetSprite;default;
// Конструктор
// Создает и инициализирует экземпляр списка спрайтов, связанного с данной канвой
constructor Create(const aCanvas:Controls.TControlCanvas);
…
end;
В Delphi модификатор доступа private применяется к членам класса, которые доступны лишь тому же модулю, в котором описан сам класс, но недоступны другим модулям программы. Обычно поля класса имеют уровень доступа private. Члены класса с уровнем доступа public доступны любой части программы. Свойства класса обычно имеют уровень доступа public. Так поле FCanvas (идентификаторы полей в Delphi принято начинать буквой F от field – поле) имеет уровень доступа private, но свойство Canvas открыто для доступа. Через свойство Canvas можно прочесть поле FCanvas, но нельзя изменить его значение. Так свойства могут регулировать доступ к полям.
Что касается методов, то их разделение по уровням доступа зависит от логики класса. Так, метод GetSprite(aZ:integer):TSprite класса TSpriteList «спрятан» от внешнего доступа под модификатором private. Его роль ограничивается обеспечением доступного свойства Sprites[aZ:integer] возвращаемым значением – спрайтом с индексом aZ из списка. Другие методы класса TSpriteList имеют открытый доступ. Среди них конструктор класса Create, создающий экземпляр объекта и инициализирующий его поля. Параметром конструктора является объект типа TControlCanvas из библиотечного модуля Controls. Объекты этого типа предоставляют спрайтам область изображения - прямоугольник с известными границами в окне приложения и инструменты изображения – кисть и карандаш с цветовой палитрой.
Модификатор const, указанный в описании параметра конструктора и многих других методов, не является обязательным. Он указывает лишь на то, что метод обязуется внутри не изменять значения параметра, передаваемого ему с этим модификатором.
Модификатор default в свойстве Sprites указывает на то, что доступ к объектам класса TSpriteList может осуществляться через свойство Sprites как к элементам массива – в индексном виде.
В коде настоящего модуля имена, описанные в других модулях, специально записаны в расширенном формате с тем, чтобы явно указать их принадлежность. Например, имя типа TControlCanvas, описанного в модуле Controls, записано в расширенном виде Controls.TControlCanvas. Вообще говоря, расширенное имя можно сократить, убрав имя модуля, если отсутствует конфликт имен.
Метод
procedure BeforeDestruction; override;
имеет модификатор override. Это означает, что метод BeforeDestruction является виртуальным и унаследован от предка класса TSpriteList, где он описан как виртуальный (virtual). Предком класса TSpriteList является класс TObject.
Другие методы
procedure DeleteSprite(const aZ:integer); virtual;
procedure Clear; virtual;
описаны как виртуальные в самом классе TSpriteList. У наследника TTracedSpriteList, эти же методы преобретают модификатор override.
Рассмотрим еще один фрагмент кода, относящийся к описанию Tsprite и следующий за описанием класса TSpriteList.
// Тип обработчика события, наступающего перед смещением спрайта
OnMoveEvent=function(Sender:TSprite;var NewLocation:Types.TPoint):Boolean of object;
// Абстрактный класс спрайта, регулирующий изображение и перемещение спрайта
TSprite=class(TObject)
private
…
// Конструктор
// Создает и инициализирует спрайт, принадлежащий списку Sprites
// с прямоугольником SpriteRect
constructor Create(const SpriteRect:Types.TRect;const Sprites:TSpriteList);
protected
…
// Формирует реальное изображение спрайта (в этом классе метод абстрактный)
procedure PaintPicture;virtual;abstract;
public
…
end;
Здесь
· Тип функции OnMoveEvent, описанный с модификатором of object, означает, что это тип метода класса, а не просто тип какой-то отдельной функции. Разница в том, что метод класса обязательно имеет один скрытый параметр Self - экземпляр класса, который его вызывает. У обычных процедур и функций такого параметра нет. Обработчики событий в Delphi обычно имеют тип метода. Тогда в них можно подставить ссылку на метод либо формы приложения, либо другого класса, использующего объявленное событие в своих целях.
· В заголовке описания класса TSprite в скобках указан предок TObject, хотя такое указание отсутствует в описании класса TSpriteList. В Delphi отсутствие предка по умолчанию означает, что предком является класс TObject. Так что в описании класса TSprite ссылку на TObject можно также опустить.
· Конструктор класса TSprite помещен в раздел private. Это делает невозможным создание экземпляров отдельных спрайтов из кода, написанного вне модуля uSprite. Логика классов TSprite и TSpriteList предполагает, что созданием спрайтов занимается только метод Add класса TSpriteList, который только и вызывает конструктор экземпляров класса TSprite.
· В описании класса TSprite присутствуют методы с уровнем доступа protected. Эти методы и вообще члены класса с доступом protected доступны любому предку класса TSprite, даже если они описаны в других модулях, но не доступны коду других классов, описанных в других модулях.
· Среди методов класса TSprite, защищенных модификатором protected есть абстрактный метод procedure PaintPicture; virtual; abstract. Он отмечен модификатором abstract. Абстрактный метод PaintPicture не имеет реализации в классе TSprite. Его реализация будет предложена наследниками. Наличие абстрактного метода делает сам класс TSprite абстрактным в том смысле, что его экземпляры не могут быть созданы.
После описания класса TSprite описаны один тип динамического массива
// Тип массива, хранящего карту следов (пикселей) спрайтов на канве
TTraceMap=Array of array of Boolean;
Тип TTraceMap описывает двумерный массив логических значений.
Динамичность массива в том, что его размер не фиксируется как постоянная величина в процессе разработки класса (design time), а определяется лишь в ходе счета (run time). Конкретные переменные, например, размеры области изображения спрайтов, приобретают реальные значения при создании экземпляра класса TTracedSpriteList=class(TSpriteList). Это происходит в методе AfterConstruction класса TTracedSpriteList, выполняющемся сразу вслед за созданием экземпляра объекта этого класса.
За описанием класса TTracedSpriteList и перед описанием класса TtracedSprite есть описание другого типа динамического массива
// Тип массива точек следа спрайта
TTracePoints=array of Types.TPoint;
Это уже одномерный массив точек - записей типа TPoint, описанных в стандартном модуле Types.
Вслед за этим описан класс
TTracedSprite=class(TSprite)
наследник класса TSprite.
Обратите внимание, что класс TTracedSprite, как и его предок TSprite, является абстрактным классом, так как не реализует абстрактный метод PaintPicture.
Вслед за описанием класса TTracedSprite расположен текст
const DefaultColor=$ffffff; //Цвет эллипса по умолчанию