Лекция № 7
Структуризация моделей программ (продолжение)
Резюме по структуризации функциональной модели:
В рамках классического структурного программирования 70-х поуровневая структуризация заключается в функциональной абстракции / декомпозиции.
Концепция интерфейса важна для технологии разработки ПП (стандартизация, совместимость, переносимость, развиваемость) - как для программных слоев, так и для более мелких компонентов, состоящих из нескольких или одного модуля.
Структуризация информационной модели
Рассмотренная функциональная абстракция должна дополняться абстракцией данных.
В классических языках (Алгол) - три способа структуризации данных:
типизация - средство разграничения видов данных и привязки к ним возможных операций - удобное средство контроля при компиляции и в период выполнения
агрегатирование - составные типы (массивы, записи) - сокращение пространства имен, индексация однородных объектов
локализация - ограничение видимости данных внутри процедур - упрятывание деталей, сокращение пространства имен и предотвращение конфликта имен. Вопрос 1.
Первые два способа ортогональны к функциональной абстракции (т.е., никак не связаны с ней). Третий способ хорошо соответствует идее сокрытия излишней информации, но подходит только для промежуточных, короткоживущих данных, привязанных к одной процедуре (локальные переменные перестают существовать после выхода из процедуры!). Долговременные данные, общие для нескольких процедур, приходится объявлять глобальными для всех процедур. Их недостаток - опасность неправильного использования.
Идея новых видов модульности в современных языках: объединять данные и обрабатывающие их процедуры и скрывать видимость всех элементов, кроме интерфейсных. Исторически впервые - в АТД (язык CLU, 1979).
Предыстория и идея абстрактных типов данных (атд)
Тип данных – это множество значений данных вместе с множеством операций, определенных на них. Вопрос 2. В ранних языках были только стандартные типы данных (integer, char и пр.). В Паскале и С появились типы, задаваемые программистом:
а) именуемые описания переменных стандартного типа (операторы type, typedef),
б) перечислимые типы и диапазоны (type, enum), где задается свое множество именуемых значений (отображаемых на подмножество целых констант). В обоих случаях определяются производные типы, наследующие множество операций базового типа. Естественное развитие: дать возможность программисту определять свои операции. Как? – описывая их процедурами. При этом любые другие операции запрещаются путем инкапсуляции (упрятывания) данных. Таким образом осуществляется абстракция данных, аналогичная функциональной абстракции.
Современные виды модульности
Модуль – общетехнический термин, означающий элемент или блок, стандартным образом стыкуемый с другими модулями для построения составной конструкции. В классических языках программирования модуль – это единица компиляции и сборки, т.е. подпрограмма или головная программа. Независимая компиляция и библиотеки модулей – основа повторного их использования. В конце 70-х появились модули, в той или иной степени реализующие концепцию АТД. Таковы АТД в CLU, модуль в Модуле-2, unit в Турбо-Паскале, пакет в Аде и файл в С. Такой модуль состоит из двух частей – интерфейса и реализации. В интерфейсном разделе (заголовочный (header) файл в С) описаны видимые данные и процедуры и импортируемые извне (# include) – вся информация, достаточная для задействования модуля. В разделе реализации – тела интерфейсных процедур и инкапсулированные данные и процедуры, защищенные от случайного неправильного использования их другими частями программы. В языке С инкапсуляция внутри файла имеет место для static данных. Вопрос 3. Пример – интерфейс АТД «стек символов»:
// файл stack.h
int stack_id, size;
int Create_stack (int size); // создает стек и возвращает его идентификатор
void Push (stack_id, char); // затолкнуть символ
char Pop (stack_id); // вытолкнуть символ
Destroy_stack (stack_id); // уничтожает стек
В файле stack.с структура данных стека объявлена как static char v [size]; и закодированы все 4 интерфейсные процедуры.
Большое преимущество – возможность раздельной компиляции .h и .c файлов.