Основы объектно-ориентированного проектирования

         

Техника подпрограммы с множественным входом


Техника, основанная на блоке COMMON, как это видно, нарушает Принцип Лингвистических Модульных Единиц. В модульной структуре системы подпрограммы, являясь концептуально связаннами, физически независимы.

Эту ситуацию можно улучшить (не убирая другие перечисленные ограничения) посредством особенности языка, легализованной в Fortran 77 - множественными точками входа в одной подпрограмме.

Это расширение, введенное, возможно, для других целей, можно использовать во благо ОО-подхода. Клиентские подпрограммы могут вызывать точки входа, как если бы они были автономными подпрограммами, и разные входы могут иметь разные аргументы. Вызов входа начинает выполнение подпрограммы с этой точки. Все входы разделяют хранимые данные подпрограммы, появляющиеся с директивой SAVE и сохраняемые от одной активизации подпрограммы к другой. Понятно, куда мы клоним: эту технику можно использовать для определения модуля, инкапсулирующего абстрактный объект, почти как в инкапсулирующем языке. Здесь модуль моделируется подпрограммой, структура данных - набором объявлений с директивой SAVE, и каждый компонент соответствующего класса в ОО-языке - входом, заканчивающимся инструкцией RETURN:

ENTRY (arguments) ... Инструкции ... RETURN

В отличие от предыдущего решения, основанного на COMMON, теперь все необходимое сосредоточено в единой синтаксической единице. В таблице 34.1 дан пример реализации стека действительных величин. Вызовы клиента выглядят следующим образом:

LOGICAL OK REAL X C OK = MAKE () OK = PUT (4.5) OK = PUT (-7.88) X = ITEM () OK = REMOVE () IF (EMPTY ()) A = B

Взглянув на этот текст, можно почти поверить, что это использование класса, или, по крайней мере, объекта, через его абстрактный, официально определенный интерфейс!

Подпрограмма в Fortran и ее точки входа должны быть все либо подпрограммами, либо функциями. Здесь, поскольку EMPTY и ITEM должны быть функциями, все другие входы должны тоже объявляться как функции, включающие MAKE, чей результат бесполезен.

Таблица 16.1. Эмуляция модуля стек в Fortran
C --РЕАЛИЗАЦИЯ C --АБСТРАКТНЫЙ СТЕК ЧИСЕЛ C INTEGER FUNCTION RSTACK () PARAMETER (SIZE=1000) C C --ПРЕДСТАВЛЕНИЕ C REAL IMPL (SIZE) INTEGER LAST SAVE IMPL, LAST C C --ВХОД С ОБЪЯВЛЕНИЯМИ C LOGICAL MAKE LOGICAL PUT LOGICAL REMOVE REAL ITEM LOGICAL EMPTY C REAL X C C -- СОЗДАНИЕ СТЕКА C ENTRY MAKE () MAKE = .TRUE. LAST = 0 RETURN C C -- ДОБАВЛЕНИЕ ЭЛЕМЕНТА C ENTRY PUT (X) IF (LAST .LT. SIZE) THEN PUT = .TRUE. LAST = LAST + 1 IMPL (LAST) = X ELSE PUT = .FALSE. END IF RETURN C --УДАЛЕНИЕ ВЕРШИНЫ C ENTRY REMOVE (X) IF (LAST .NE. 0) THEN REMOVE = .TRUE. LAST = LAST - 1 ELSE REMOVE = .FALSE. END IF RETURN C C --ЭЛЕМЕНТ ВЕРШИНЫ C ENTRY ITEM () IF (LAST .NE. 0) THEN ITEM = IMPL (LAST) ELSE CALL ERROR * ('ITEM: EMPTY STACK') END IF RETURN C C -- ПУСТ ЛИ СТЕК? C ENTRY EMPTY () EMPTY = (LAST .EQ. 0) RETURN C END

Этот стиль программирования может успешно применяться для эмуляции инкапсуляции Ada или Modula-2 в контекстах, где нет другого выбора, кроме использования Fortran. Конечно, он страдает от жестких ограничений:

  • Не разрешаются никакие внутренние вызовы: в то время как подпрограммы в ОО-классе обычно опираются друг на друга для реализации, вызов входа той же подпрограммы будет понят как рекурсия - проклятие для Fortran - и бедствие во время выполнения во многих реализациях.
  • Как отмечалось, этот механизм строго статичен, поддерживая только один абстрактный объект. Он может быть обобщен преобразованием каждой переменной в одномерный массив. Но не существует переносимой поддержки для создания динамического объекта.
  • На практике некоторые среды Fortran не слишком хорошо работают с множественными входами подпрограмм.
  • Наконец, сама идея использования языкового механизма для целей, отличных от проектируемых, порождает опасность путаницы.


Содержание раздела