Эмуляция объектной технологии в не ОО-средах
Уровни языковой поддержки
Оценивая возможности поддержки ОО-концепций языками программирования, можно разделить их на три широкие категории (игнорируя самый низкий уровень, в основном, ассемблерных языков, не поддерживающих даже понятия подпрограммы):
- К функциональному уровню отнесем языки, где единицей декомпозиции является подпрограмма - функциональная абстракция, описывающая шаг обработки. Абстракция данных, если она есть, обрабатывается через определения структур данных, либо локальных для подпрограммы, либо глобальных.
- Языки инкапсулирующего уровня позволяют группировать подпрограммы и данные в синтаксической единице, называемой модулем или пакетом. Обычно такие единицы допускают независимую компиляцию. Довольно подробно это обсуждалось при рассмотрении языка Ada.
- На третьем уровне идут ОО-языки. Здесь не место обсуждать, что дает право языку на такое звание. Это вопрос детально рассмотрен в лекции 2 курса "Основы объектно-ориентированного программирования", здесь же отметим необходимость поддержки классов, наследования, полиморфизма и динамического связывания.
Для категории инкапсулирующих языков, поддерживающих механизм абстракции данных, но не поддерживающих классы, наследование, полиморфизм и динамическое связывание, в литературе используется термин основанный на объекте, введенный в статье Питера Вегнера. Поскольку слова основанный и ориентированный близки и не отражают концептуальной разницы между языками, довольно трудно объяснить, особенно новичкам, суть термина "основанный на объекте". Поэтому я решил придерживаться выражений "инкапсулирующие языки" и "объектно-ориентированные языки". |
Еще немного о терминологии. Термин "функциональные языки" двусмысленен, поскольку в литературе он применяется к классу языков, основанных на математических принципах и часто прямо или косвенно происходящих от Lisp, а этот язык использует функции, свободные от побочных эффектов, вместо императивных конструкций, таких как процедуры и присваивания. Во избежание путаницы в данной книге для обозначения этого стиля программирования всегда используется термин "аппликативный". В нашем толковании "функционального языка" слово функция противопоставляется не процедуре, а объекту. Путаница еще более усугубляется употреблением термина "процедурный язык" как синоним "не объектно-ориентированный"! Для такой терминологии нет оснований - для нас "процедурный" является синонимом "императивный", в противоположность термину "аппликативный". Все обычные ОО-языки, включающие нотацию этой книги, явно процедурные.
Общее замечание по ОО-эмуляции. В своей основе объектная технология - это "программирование с абстрактными типами данных". Даже на функциональном уровне можно применять рудиментарную форму этой идеи, определив набор строгих методологических правил, требующих вызова подпрограмм для доступа к данным. Предполагается, что начинать надо с ОО-построения, определяющего АТД и его компоненты. Затем пишется набор подпрограмм, представляющих эти компоненты - put, remove, item, empty, как в нашем стандартном примере стека. Далее требуется, чтобы все клиентские модули использовали только эти подпрограммы. При отсутствии языковой поддержки, но при условии, что все в команде подчиняются навязанным правилам, это можно рассматривать как начало объектного подхода. Назовем эту технику дисциплинарным подходом.
ОО-программирование на языке Pascal?
Язык Pascal, введенный в 1970г. Никласом Виртом, много лет являлся доминирующим языком начального обучения программированию на факультетах информатики и оказал большое влияние на построение последующих языков. Pascal - это функциональный язык в только что определенном смысле.
Собственно Pascal
Многое ли из ОО-подхода можно реализовать в Pascal?
К сожалению, немногое. Структура программы в Pascal основана на совершенно другой парадигме. Программа на языке Pascal состоит из последовательности описательных разделов, следующих в неизменном порядке: метки, константы, типы, переменные, подпрограммы (процедуры и функции) и раздела выполняемых инструкции. Сами подпрограммы рекурсивно имеют ту же структуру.
Это простое правило облегчает однопроходную компиляцию. Но любая попытка использования ОО-техники обречена. Рассмотрим, что нужно для реализации ADT, например, стека, представленного массивом: несколько констант, задающих размер массива, тип, описывающий элементы стека, несколько переменных, таких как указатель на вершину стека и несколько подпрограмм, задающих операции АТД. В Pascal эти элементы будут разбросаны по разделам: все константы вместе, все типы вместе и т. д.
Результирующая программная структура противоположна ОО-проектированию. Использование Pascal противоречит принципу Лингвистических Модульных Единиц: любая политика модульности должна поддерживаться доступными конструкциями языка.
Итак, если рассматривать официальный стандарт Pascal, то сделать можно немногое, не считая использования дисциплинарного подхода.
Модульные расширения языка Pascal
За пределами стандарта Pascal многие коммерчески доступные версии снимают ограничения на порядок объявлений и включают поддержку модульности, включая независимую компиляцию. Такие модули могут содержать константы, типы и подпрограммы. Эти языки более гибкие и сильные, чем стандартный Pascal, сохраняют имя Pascal. Они не стандартизированы, и в действительности больше напоминают инкапсулирующие языки, такие как Modula-2 или Ada, обсуждаемые в предыдущей лекции.
ОО-расширения языка Pascal
Некоторые компании предложили ОО-расширения языка Pascal, широко известные как "Object Pascal". Две версии особенно значимы:
- версия Apple, происходящая от языка, первоначально называвшегося Clascal и используемого для компьютера Macintosh и его предшественника, - Lisa;
- версия Borland Pascal, адаптированная в среде Borland Delphi.
Наше обсуждение не затрагивает эти языки, так как реально их связь с Pascal проявляется только в имени, стиле синтаксиса и статически типизированном подходе. В частности, Borland Pascal - это ОО-язык с обработкой исключений. Он не поддерживает механизмов универсальности, утверждений, сборки мусора и множественного наследования.