Иллюстрированный самоучитель по Turbo Pascal

Полиформные коллекции

Как уже говорилось, коллекции Turbo Vision обладают свойством полиморфизма – они позволяют хранить различные объекты. Поскольку каждый объект имеет все необходимые для него поля и методы, работа с полиморфными коллекциями не создает дополнительных проблем. Действительно, в полиморфной коллекции Вам обычно нет нужды следить за тем, какого типа объект хранится в том или ином элементе – достаточно вызвать нужный виртуальный метод, чтобы осуществить над элементом требуемые действия.

Рассмотрим следующий пример. Пусть необходимо создать и использовать библиотеку графических примитивов (точки, окружности, прямоугольники и т.п.). Каждый из этих элементов может отличаться своим набором полей и методов. Однако некоторые методы выполняют над объектами однотипные действия, такие, например, как создание нового объекта или его вычерчивание на экране. Если эти методы сделать виртуальными и инкапсулировать в объект-предок, каждый из его потомков сможет осуществить нужные действия одинаковым способом.

Для нашего примера можно создать следующий объект-родитель:

type
PGraphObject = TGraphObject;
TGraphObject = object (TObject)
X, Y: Integer; {Координаты характерной точки}
Constructor Init; {Создание объекта}
Procedure Draw; Virtual; {Вычерчивание}
end;

Объект TGraphObject содержит общие для всех потомков поля и методы. Заметим, что методы Init и Draw должны перекрываться в объектах-потомках, поэтому их содержимое не имеет значения. Однако полезно вынести в них некоторые общие для всех потомков части программы. Например, конструктор Init может помещать в поля X и Y заданные начальные значения; если этот метод наполнить конкретным содержанием, он может использоваться во всех объектах иерархии:

Constructor TGraphObject.Init;
{Присваивает случайные значения координатам X и Y}
begin
X: = Random(GetMaxX);
Y: = Random(GetMaxY)
end;

Здесь GetMaxX, GetMaxY – максимальные координаты графического экрана.

Виртуальный метод Draw весьма специфичен: его конкретная программная реализация будет существенно зависеть от типа объекта. Поэтому объявим этот метод абстрактным:

Procedure TGraphObject.Draw;
{Абстрактный метод для вычерчивания графического примитива}
begin
Abstract
end;

Как видим, тело этого метода содержит обращение к глобальной процедуре Abstract, которая аварийно завершает выполнение программы и выдает соответствующую диагностику, если в программе используется вызов метода TGraphObject.Draw. Таким стандартным способом Turbo Vision сообщает пользователю о некорректности программы. Вы можете сделать тело этого метода другим, если Вас не устраивают стандартные действия, однако во всех случаях имеет смысл предусмотреть возможность некорректного вызова абстрактного метода, даже если вновь создаваемая библиотека будет использоваться только Вами – это значительно облегчит отладку программы.

Создадим три потомка от TGraphObject:

type
PPoint =TPoint;
TPoint = object (TGraphObject) {Точка}
Procedure Draw; Virtual;
end;
PCircle = TCircle; {Окружность}
TCircle = object (TGraphObject)
R: Integer;
Constructor Init;
Procedure Draw; Virtual;
end;
PRectangle = TRectangle; {Прямоугольник}
TRectangle = object (TGraphObject)
W, H: Integer;
Constructor Init;
Procedure Draw; Virtual;
end;

Объект TPoint (точка) не имеет новых полей и поэтому лишь перекрывает абстрактный метод TGraphObject.Draw:

Procedure TPoint.Draw; {Выводит точку на экран}
begin
PutPixel (X, Y, White)
end;
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.