Это непростой вопрос. Наверное, в зависимости от того, что вы пишете. Насколько там простые или сложные объекты.
Подход к ООП в оригинальном Обероне и Обероне-07:
(Кстати, Оберон-07 в своём сообщении о языке не считается таковым, он просто называется «Оберон», а затем написано, что это ревизия от такого-то числа).
Процедурные переменные могут отлично работать во многих случаях. Они проще с точки зрения упрощения языка, то есть для них не надо знать каких-то дополнительных конструкций языка, весь ООП пишется теми же средствами, как и без использования ООП. В сравнении с другими способами ООП на Обероне здесь есть некоторая гибкость. (Можно поэкспериментировать, придумать что-то своё.) Есть различные подходы: процедурные переменные в каждой записи, отдельная запись с методами для всего типа, шины сообщений (особенно ценная вещь, даже в КП и Обероне-2).
Процедурные переменные в каждой записи
MODULE Bitmaps;
TYPE
Bitmap* = POINTER TO BitmapDesc;
BitmapDesc* = RECORD
Line*: PROCEDURE(b: Bitmap; x1, y1, x2, y2: INTEGER);
END;
PROCEDURE Line(b: Bitmap; x1, y1, x2, y2: INTEGER);
BEGIN
END Line;
PROCEDURE InitBitmap*(VAR b: BitmapDesc); (* вариант: (b: Bitmap) ... *)
BEGIN
b.Line := Line
END InitBitmap;
PROCEDURE NewBitmap*(): Bitmap;
VAR b: Bitmap;
BEGIN
NEW(b);
InitBitmap(b^); (* ...тогда здесь (b) *)
RETURN b
END NewBitmap;
END Bitmaps.
(* Как пользоваться (в другом модуле): *)
PROCEDURE Test;
VAR b: Bitmaps.Bitmap;
BEGIN
b := Bitmaps.NewBitmap();
b.Line(b, 5, 5, 90, 90)
END Test;
Отдельная запись с методами для всего типа
Шины сообщений
Подход к ООП в Обероне-2 и Компонентном Паскале:
Связанные с типом процедуры (type-bound procedures) проще с точки зрения непосредственно их использования, так как они поддерживаются языком. Язык при этом становится чуточку сложнее, так как в нём появляются процедуры с двумя наборами скобок в заголовке:
PROCEDURE (b: Bitmap) Line(x, y: INTEGER);
Здесь приходится решать ещё один вопрос: выполнить ли данную процедуру обработки записи в виде обычной процедурой или выполнить её в виде процедуры, связанной с типом. Кстати, при этом процедуры, связанные с типом, который представляет собой нерасширяемую запись, ничем в машинном коде не отличаются от обычных процедур, а значит представляют собой просто альтернативную запись того же, что можно было сделать и обычной процедурой (такое иногда называют «синтаксическим сахаром»). Последнее относится только к КП.
Я проводил некоторые практические исследования этого вопроса. К однозначным выводам пока не пришёл. Я писал библиотеку графического интерфейса пользователя с нуля в каждом из этих четырёх стилей ООП, чтобы посмотреть, может ли нестандартное программирование ООП превратиться в удобную привычку и чтобы сравнить получившийся код на предмет его понятности. Из очевидного: Подход КП и Оберон-2 намного лаконичнее.
Ещё есть такой язык как Объективный Оберон (Objective Oberon, предтеча Оберона-2). В нём связанные с типом процедуры указаны внутри объявления типа, а затем ниже повторяются ещё раз. Как в Объективном Паскале или в Си++ (в одном из вариантов написания методов в Си++).
И, наконец, есть язык Активный Оберон (Active Oberon), в котором наряду со словом RECORD есть слово OBJECT, а связанные с типом процедуры указываются целиком внутри конструкции OBJECT, как в одном из вариантов написания на Си++.
28 декабря 2020 г.
г. Рига, ЛССР