Код:
MODULE Interface;
(* Данный модуль содержит общее для системы определение интерфейса Writer.
Для простоты интерфейс предоставляет единственный метод Write. *)
TYPE
Writer* = POINTER TO ABSTRACT RECORD
END;
PROCEDURE (w: Writer) Write* (), NEW, ABSTRACT;
END Interface.
MODULE Class;
(* Модуль Class содержит объект Object, поддерживающий интерфейс Interface.Writer. *)
IMPORT
Interface;
TYPE
Object* = POINTER TO RECORD
writer-: Interface.Writer;
END;
ObjectWriter = POINTER TO RECORD (Interface.Writer)
this: Object;
END;
PROCEDURE (ow: ObjectWriter) Write ();
(** Реализация интерфейса Interface.Wirter для объекта Class.Object. *)
BEGIN
(* TODO: сохранить данные ow.this *)
END Write;
PROCEDURE NewObject* (): Object;
(** Конструктор для типа Object. *)
VAR
ow: ObjectWriter;
res: Object;
BEGIN
NEW(ow);
NEW(res);
ow.this := res;
res.writer := ow;
RETURN res
END NewObject;
END Class.
Что обычно требуется от интерфейса:
- чтобы можно было включать объект (Object) в список разнородных объектов (не обязательно унаследованных от одного общего предка), по признаку поддержки интерфейса (Writer);
- чтобы при компиляции выдавалась ошибка, если не все методы интерфейса реализованы.
Первое возможно благодаря опубликованному полю writer. Можно создать массив или список объектов типа Interface.Writer, при этом скрытые поля this будут указывать на реальные объекты произвольных типов, с которыми далее можно вести работу через методы интерфейса - например, в цикле вызвать для всех сохранение в файл.
Второе тоже поддерживается, так как КП требует реализации всех абстрактных унаследованных методов при объявлении не-абстрактного наследника.
Отличие от Java также заключается в том, что для каждого экземпляра объекта Object мы вынуждены создавать экземпляры ObjectWriter для всех поддерживаемых интерфейсов. Ведь у нас роль интерфейса берёт на себя отдельный самостоятельный объект. Насколько я знаю, в Java все проверки интерфейсов проводятся во время компиляции, и во время исполнения везде используется ссылка на сам объект Object, без дополнительной нагрузки на динамическую память для создания посредников. Как вариант, вместо поля writer можно использовать методы типа GetWriter(): Interface.Writer, и создавать экземпляры ObjectWriter только когда и если они потребуются.
Ещё интерфейсы используются для маркировки объектов. Заводится пустой интерфейс (без методов и полей) с говорящим названием, например, Serializable, и во время выполнения система ищет объекты, реализующие такой интерфейс, и воспринимает это как знак того, что с объектом нужно сделать что-то особенное (например, сохранить его поля в БД при выгрузке программы). В ББ это тоже можно сделать средствами модуля Meta, при этом, наверное, не нужно даже создавать экземпляр интерфейсного объекта, достаточно объявить поле соответствующего типа.
PS: можно в Вики.
UPD: Вспомнил про абстрактные методы и заменил в определении метода Interface.Writer.Write ключевое слово EMPTY на ABSTRACT.