Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Delphi_3.doc
Скачиваний:
44
Добавлен:
28.03.2015
Размер:
1.71 Mб
Скачать

6.7. Реализация нескольких интерфейсов

Один класс может содержать реализацию нескольких интерфейсов. Такая возможность позволяет воплотить в классе несколько понятий. Например, класс TTextReader — "считыватель табличных данных" — может выступить еще в одной роли — "считыватель строк". Для этого он должен реализовать интерфейс IStringIterator:

type

IStringIterator = interface

function Next: string;

function Finished: Boolean;

end;

Интерфейс IStringIterator предназначен для последовательного доступа к списку строк. Метод Next возвращает очередную строку из списка, метод Finished проверяет, достигнут ли конец списка.

Реализуем интерфейс IStringIterator в классе TTextReader таким образом, чтобы последовательно считывались значения из ячеек таблицы. Например, представьте, что в некотором файле дана таблица:

Aaa Bbb Ccc

Ddd Eee Fff

Ggg Hhh Iii

Чтение этой таблицы через интерфейс IStringIterator вернет следующую последовательность строк:

Aaa

Bbb

Ccc

Ddd

Eee

Fff

Ggg

Hhh

Iii

Ниже приведен программный код, обеспечивающий поддержку интерфейса IStringIterator в классе TTextReader:

type

TTextReader = class(TInterfacedObject, ITextReader, IStringIterator)

FColumnIndex: Integer;

function Next: string;

function Finished: Boolean;

...

end;

...

function TTextReader.Next: string;

begin

if FColumnIndex = ItemCount then // Если пройден последний элемент текущей строки,

begin // то переходим к следующей строке таблицы

NextLine;

FColumnIndex := 0;

end;

Result := Items[FColumnIndex];

FColumnIndex := FColumnIndex + 1;

end;

function TTextReader.Finished: string;

begin

Result := EndOfFile and (FColumnIndex = ItemCount);

end;

Теперь объекты класса TTextReader совместимы сразу с тремя типами данных: TInterfacedObject, ITextReader, IStringIterator.

var

Obj: TTextReader;

Reader: ITextReader;

Iterator: IStringIterator;

begin

...

Reader := Obj; // Правильно

Iterator := Obj; // Правильно

...

end;

В одном случае объект класса TTextReader рассматривается как считыватель табличных данных, а в другом случае — как обычный список строк с последовательным доступом. Например, если есть две процедуры:

procedure LoadTable(Reader: ITextReader);

procedure LoadStrings(Iterator: IStringIterator);

то объект класса TTextReader можно передать в обе процедуры:

LoadTable(Obj); // Obj воспринимается как ITextReader

LoadStrings(Obj); // Obj воспринимается как IStringIterator

6.8. Реализация интерфейса несколькими классами

Несколько совершенно разных классов могут содержать реализацию одного и того же интерфейса. С объектами таких классов можно работать так, будто у них есть общий базовый класс. Интерфейс выступает аналогом общего базового класса.

Рассмотрим пример. Представьте, что есть два класса: TTextReader и TIteratableStringList:

type

TTextReader = class(TInterfacedObject, ITextReader, IStringIterator)

...

end;

TIteratableStringList = class(TStringList, IStringIterator)

...

end;

Схематично полученную иерархию классов можно представить так (рисунок 6.2):

Рисунок 6.2. Иерархия классов, реализующих интерфейсы. Сплошными линиями отмечено наследование классов, а пунктирными линиями — реализация интерфейсов классами.

Объекты классов TTextReader и TIteratableStringList несовместимы между собой. Тем не менее, они совместимы с переменными типа IStringIterator. Это значит, что если есть процедура:

procedure LoadStrings(Iterator: IStringIterator);

то вы можете передавать ей объекты обоих упомянутых классов в качестве аргумента:

var

ReaderObj: TTextReader;

StringsObj: TIteratableStringList;

begin

...

LoadStrings(ReaderObj); // Все правильно

LoadStrings(StringsObj); // Все правильно

...

end;