Турбо Паскаль 6.0

         

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


Вы видите, что коллекции могут хранить любой тип данных динамически и что они содержат методы, помогающие Вам эффективно обращаться к данным коллекции. В действительности TCollection определяете 23 метода. Когда Вы используете коллекции в Ваших программах, Вы удивитесь скорости их работы. Они спроектированы для обеспечения гибкости и реализованы на удивление быстрыми. Сейчас Вы увидите реальную мощь коллекций: элементы могут обрабатываться полиморфно. Это означает, что Вы можете делать больше, чем просто сохранять тип объекта в коллекции; Вы можете хранить множество различных типов объектов из любого места в иерархии объектов. В примерах, которые мы рассматривали до сих пор, все элементы коллекции были одного типа. Но коллекции могут хранить любые объекты, порожденные от TObject и Вы можете свободно смешивать эти объекты. Обычно Вам необходимо иметь объекты с определенным сходством. Как пример рассмотрим программу, которая помещает 3 различных графических объекта в коллекцию. Затем итератор ForEach используется для прохода по коллекции и отображения каждого объекта. Этот пример использует модуль Graph и драйверы BGI, поэтому выо время компиляции GRAPH.TPU должен быть в текущем справочнике или в справочниках модулей (Options/Directories/Unit Directory). При выполнении программы перейдите в справочник, содержащий драйверы .BGI или модифицируйте вызов InitGraph, чтобы указать их расположение (например C:\TP\BGI). Вначале определим объект абстрактного предка.

{ TVGUID20.PAS } type PGraphObject = ^TGraphObject; TGraphObject = object(TObject) X,Y: Integer; constructor Init; procedure Draw; virtual; end;

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

PGraphPoint = ^TGraphPoint; TGraphPoint = object(TGraphObject) constructor Init; procedure Draw; virtual; end;

PGraphCircle = ^TGraphCircle; TGraphCircle = object(TGraphObject) Radius: Integer; constructor Init; procedure Draw; virtual; end;


PGraphRect = ^TGraphRect; TGraphRect = object(TGraphObject) Width, Height: Integer; constructor Init; procedure Draw; virtual; end;

Эти 3 объекта наследуют поля X и Y от PGraphObject, но имеют различные размеры. PGraphCircle добавляет Radius, а PGraphRect добавляет Width и Height. Следующий код создает коллекцию:

. List := New(PCollection, Init(10, 5));

for I := 1 to 20 do begin case I mod 3 of 0: P := New(PGraphPoint, Init); 1: P := New(PGraphCircle, Init); 2: P := New(PGraphRect, Init); end; List^.Insert(P); end; .

Как Вы видите, цикл for вставляет 20 графических объектов в коллекцию List. Все, что Вы знаете, это то, что каждый объект в List - какого-то из типов от TGraphObject. После того, как они вставлены в коллекцию, неважно какой из элементов окружность, точка и прямоугольник. Благодаря полиморфизму Вам не нужно знать сколько данных содержит каждый объект и какой код (Draw) ему требуется. Просто пройдем по коллекции, используя метод итератора и каждый объект отобразит себя сам:

procedure DrawAll(C: PCollection);

procedure CallDraw(P : PGraphObject); far; begin P^.Draw; end;

begin { DrawAll } C^.ForEach(@CallDraw); end;

var GraphicsList: PCollection; begin . DrawAll(GraphicsList); . end.

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


Содержание раздела