Опубликован: 17.10.2005 | Доступ: свободный | Студентов: 8823 / 588 | Оценка: 4.38 / 4.10 | Длительность: 41:16:00
ISBN: 978-5-7502-0255-3
Специальности: Программист
Лекция 7:

Статические структуры: классы

Компоновка системы

Как практически реализовать процесс компоновки системы?

Допустим, что операционная система использует обычный способ хранения исходных текстов классов в файлах. Инструментальному средству компоновки (компилятор, интерпретатор) необходима следующая информация:

  • (A1) Имя корневого класса.
  • (A2) Генеральная совокупность (universe) файлов, содержащих тексты классов, необходимых корневому.

Эта информация не должна содержаться непосредственно в исходных текстах классов. Идентификация класса как корневого в его исходном тексте (А1) нарушает принцип отсутствия основной программы. Включение в исходные тексты классов информации о местонахождении соответствующих файлов означало бы жесткую привязку к файловой системе и, очевидно, является неприемлемым решением. Если размещение изменить, то использование таких классов становится невозможным.

Из этих рассуждений следует, что для сборки системы необходима информация, размещенная вне исходных текстов классов. Для обеспечения такой информацией будем использовать небольшой управляющий язык под названием Lace. Рассмотрим процесс сборки, но сразу отметим, что детали Lace совершенно несущественны в контексте ОО-подхода. Язык Lace просто конкретный пример управляющего языка, позволяющего сохранить автономность и возможность повторного использования классов, используя некий механизм для сборки файлов системы.

Рассмотрим типичный документ Lace, так называемый файл Ace:

system painting root
   GRAPHICS ("painting_application")
cluster
   base_library: "\ library\ base";
   graphical_library: "\ library\ graphics";
   painting_application: "\ user\ application"
end -- system painting

Предложение cluster определяет генеральную совокупность файлов, содержащих тексты классов. Оно содержит список кластеров. Кластер - это группа связанных классов, представляющих подсистему или библиотеку. (Модель кластеров обсуждается в лекции 10 курса "Основы объектно-ориентированного проектирования")

Операционные системы, такие как Windows, VMS или Unix, содержат удобный механизм поддержки кластеров - подкаталоги. Их файловые системы имеют древовидную структуру. Конечные узлы дерева (листья), называемые "обычными файлами", содержат непосредственно информацию, а промежуточные узлы, подкаталоги, содержат наборы файлов, состоящие из обычных файлов и подкаталогов.

Структура каталогов

Рис. 7.7. Структура каталогов

Можно ассоциировать каждый кластер с подкаталогом. В Lace используется следующее соглашение: каждый кластер, например base_library, имеет связанный с ним подкаталог, имя которого дано в двойных апострофах - " \ library\ base ". Такое соглашение об именах файлов используется в Windows ( \dir1\dir2\ ...) и здесь приведено только ради примера. Соответствующие имена Unix получаются заменой символов обратной косой черты на обычную.

Можно использовать иерархию подкаталогов для определения иерархии кластеров. Кроме того, Lace поддерживает понятие субкластера, что позволяет определить логическую структуру иерархии вложенных кластеров независимо от их физического положения в файловой системе.

Каталоги, перечисленные в предложении cluster, могут содержать файлы всех типов. Для работы с генеральной совокупностью процессу компоновки системы необходима информация о том, какие из файлов содержат тексты классов. Используем простое соглашение - текст некоторого класса с именем NAME размещается в файле name. e (нижний регистр). В этом случае, генеральная совокупность представляет собой набор файлов с именами вида name. e в каталогах, перечисленных в предложении cluster.

Предложение root Lace служит для задания корневого класса системы. В данном случае корневым является класс GRAPHICS и он находится в кластере painting_application. Если только один класс в генеральной совокупности называется GRAPHICS, то нет необходимости указывать кластер.

Предположим, что компилятор начинает создание системы, описанной в приведенном файле Ace. Далее предположим, что ни один из файлов системы еще не откомпилирован. Компилятор находит текст корневого класса GRAPHICS в файле graphics. e кластера painting_application, который размещается в каталоге \user\application. Анализируя текст класса GRAPHICS, компилятор находит имена классов, которые необходимы GRAPHICS и ведет поиск файлов с соответствующими именами в каталогах трех кластеров. Далее этот поиск повторяется до тех пор, пока не будут обнаружены все классы, прямо или косвенно необходимые корневому классу GRAPHICS.

Важнейшей особенностью этого процесса является возможность его автоматизации. Разработчику ПО не нужно составлять списки зависимых модулей, известных как "Make-файлы", или указывать в каждом файле имена файлов, необходимых для его компиляции ("директивы Include" в C и C++). Кроме своей утомительности процесс создания этой информации вручную является потенциальным источником ошибок. Единственное, что самостоятельно не сможет определить ни одна утилита - это имя корневого класса и размещение необходимых классов в файловой системе.

Для дальнейшего упрощения работы программиста хороший компилятор должен уметь создавать шаблоны файлов Ace, предложение cluster которых включает базовые библиотеки (ядро, фундаментальные структуры данных и алгоритмы, графика и т. д.) и указание на текущий каталог. В этом случае разработчику остается только указать имя системы и ее корневого класса без необходимости глубокого знания синтаксиса Lace.

Конечным продуктом процесса компиляции является исполняемый файл, имя которого совпадает с именем системы в файле Ace, в данном примере - painting.

Язык содержит ряд других простых конструкций, поддерживающих управление действиями инструментальных средств компоновки, в частности директив компилятора и уровней контроля утверждений. При дальнейшем изучении ОО-метода некоторые из них будут использованы. Уже отмечалось, что Lace поддерживает понятие логического субкластера и может использоваться для описания комплексных структур, включая подсистемы и многоуровневые библиотеки.

Использование независимого от языка разработки языка описания системы аналогичного Lace позволяют классам оставаться системно независимыми. Классы являются компонентами ПО, аналогичными электронным микросхемам, и система собрана из конкретного набора классов подобно компьютеру, собранному из определенного набора микросхем.

Классическое "Hello"

Повторное использование замечательная вещь, но иногда надо решить очень простую задачу, например вывести строку. Интересно, как написать такую "программу". После введения понятия системы можно ответить и на этот животрепещущий вопрос.

Следующий маленький класс содержит процедуру, выводящую строку:

class SIMPLE creation
   make
feature
   make is
         -- Вывод строки.
      do
         print_line ("Hello Sarah!")
      end
end

Процедура print_line с параметром некоторого типа выводит значение соответствующего объекта, в данном случае строки. Другая процедура с именем print делает то же самое, но без перехода на новую строку. Обе процедуры доступны во всех классах и унаследованы от универсального предка GENERAL, обсуждаемого далее. (О классе GENERAL см. "Универсальные классы", "Техника наследования" )

Для получения системы, которая будет выводить данную строку необходимо сделать следующее:

  • (E1) Поместить текст класса в файл simple. e.
  • (E2) Запустить компилятор.
  • (E3) Если файл Ace заранее не создан, то можно запросить автоматическое создание шаблона и в режиме его редактирования заполнить имя корневого класса - SIMPLE, системы - my_first и указать каталог кластера.
  • (E4) После выхода из редактора компилятор осуществит компоновку системы и создаст исполняемый файл my_first.
  • (E5) Выполнить my_first. В режиме командной строки необходимо просто ввести my_first. В системах с графическим интерфейсом появится новая пиктограмма с именем my_first и запуск программы производится двойным щелчком на ней.

В результате на консоли появится сообщение:

Hello Sarah!

Структура и порядок: программист в роли поджигателя

Общую картину процесса построения ПО ОО-методом мы уже знаем. Нам также известно, как восстановить цепочку событий, связанную с выполнением некоторой операции. Рассмотрим операцию:

[A]
   x.g (u, v, ...)

присутствующую в тексте подпрограммы r класса C и предположим, что x это атрибут. Как и когда она будет выполняться? Класс C должен быть включен в систему, скомпонованную затем с помощью соответствующего файла Ace. Далее следует запустить выполнение системы, которое начнется с создания экземпляра корневого класса. Корневая процедура создания должна выполнить одну или более операций, которые прямо или косвенно создадут объект C_OBJ - экземпляр класса C, а затем выполнят вызов:

[B]
a.r (...)

где a присоединено к C_OBJ. Далее вызов [A] выполнит g с заданными аргументами, используя в качестве цели объект, присоединенный к полю x объекта C_OBJ.

Итак, теперь мы знаем, как восстановить точную последовательность событий, происходящих в процессе выполнения системы. Подразумевается, что мы видим систему целиком. Текст одного класса, естественно, не позволяет определить порядок, в котором клиенты будут вызывать его подпрограммы. В этом случае единственная доступная для обозрения последовательность событий это порядок, в котором выполняются инструкции в теле данной подпрограммы.

Даже на уровне системы структура настолько децентрализована, что задача точного определения порядка операций, безусловно разрешимая, практически оказывается очень сложной. Важно то, что это и не очень интересно. Необходимо помнить, что корневой класс является весьма поверхностным свойством системы. Это частный выбор, сделанный уже после формирования набора классов. Всегда есть возможность достаточно просто изменить выбор корневого класса.

Этот уход от упорядочения является частью объектной технологии и стимулирует создание децентрализованной архитектуры систем. В центре внимания не "порядок выполнения программы", а функциональные возможности набора классов. "Порядок", в котором эти возможности будут реализованы в процессе выполнения конкретной системы, является вторичным свойством. (См. "Преждевременное упорядочение", "К объектной технологии" )

Данные наблюдения позволяют рассматривать роль программиста как пиротехника или человека, разжигающего огромный костер. Он складывает дрова, следя за тем, чтобы все компоненты были готовы для компоновки и необходимые связи присутствовали. Далее он зажигает спичку и следит за огнем. Если структура правильно подготовлена, то нет необходимости стараться предсказать последовательность возгораний. Достаточно знать, что каждая часть, которая должна вспыхнуть, загорится и это произойдет не раньше положенного времени.

Александр Шалухо
Александр Шалухо
Анатолий Садков
Анатолий Садков

При заказе pdf документа с сертификатом будет отправлен только сертификат или что-то ещё?