Один класс может содержать реализацию нескольких интерфейсов. Такая возможность позволяет воплотить в классе несколько понятий. Например, класс TTextReader — "считыватель табличных данных" — может выступить еще в одной роли — "считыватель строк". Для этого он должен реализовать интерфейс IStringIterator:
type IStringIterator = interface function Next: string; function Finished: Boolean; end; |
Интерфейс IStringIterator предназначен для последовательного доступа к списку строк. Метод Next возвращает очередную строку из списка, метод Finished проверяет, достигнут ли конец списка.
Реализуем интерфейс IStringIterator в классе TTextReader таким образом, чтобы последовательно считывались значения из ячеек таблицы. Например, представьте, что в некотором файле дана таблица:
Aaa Bbb CccDdd Eee FffGgg Hhh Iii |
Чтение этой таблицы через интерфейс IStringIterator вернет следующую последовательность строк:
AaaBbbCccDddEeeFffGggHhhIii |
Ниже приведен программный код, обеспечивающий поддержку интерфейса 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 воспринимается как ITextReaderLoadStrings(Obj); // Obj воспринимается как IStringIterator |