Один класс может содержать реализацию нескольких интерфейсов. Такая возможность позволяет воплотить в классе несколько понятий. Например, класс 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 |