Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по технологии программирования.doc
Скачиваний:
97
Добавлен:
02.05.2014
Размер:
69 Кб
Скачать
☆

1.2.2. Модульное программирование

Со временем в области разработки программ акценты сместились от разработки процедур к организации данных. Среди прочих моментов, здесь нашел своё отражение объективный факт возрастания размеров программ. Набор взаимосвязанных процедур и тех данных, которыми эти процедуры оперируют, часто называют модулем. Парадигма программирования несколько изменяется:

«Определите какие модули вам нужны; расчлените программу так, чтобы данные были скрыты в модулях».

Эта доктрина также известна как «принцип ограничения доступа к данным». Там, где данные не объединяются с обрабатывающими их программами, достаточно процедурного программирования. Наиболее удачный пример модуля – стек.

Модула-2 непосредственно поддерживает концепцию модульного программирования, тогда как С дает лишь возможность её использования.

Поскольку данные – это только один из элементов, которые мы стремимся «упрятать», то идея ограничения доступа к данным очевидным образом обобщается до концепции «скрытия информации», т.е. имена переменных, констант, функций и типов также можно сделать локализованным в модуле. Хотя разработка С++ не была специально ориентированна на поддержку модульного программирования, концепция класса в С++ в действительности поддерживает и модульность. Кроме этого, С++ конечно поддерживает модульность в смысле С, реализованную на базе механизма раздельной компиляции.

1.2.3. Абстракция данных.

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

class stack_id {/* … */} //stack_id– это тип

// детали реализации на этом этапе не известны

stack_idcreate_stack(intsize); // создает стек и возвращает его ид.

void push( stack_id, char);

char pop(stack_id);

destroy_stack(stack_id) // уничтожает стек

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

Во-первых, каждый модуль управления данными определенного типа должен иметь отдельный механизм для создания «переменных» этого типа.

Во-вторых, имена «переменных» такого типа неизвестно компилятору и среде программирования, и, наконец, такие «переменные» не подчиняются обычным правилам видимости и не передаются функциям подобно обычным параметрам.

Типы, создаваемые как модули, отличаются от основных типов в наиболее существенных аспектах и имеют более низкий уровень поддержки по сравнению с ними. Проблема заключается в том, что пользователь программирует в терминах небольших «дескрипторов объекта» (подобных stack_idв вышеприведенном примере), а не в терминах самих объектов. Это значит, что компилятор не сможет обнаружить «мелкие очевидные ошибки».

Например:

Voidf()

{

stack_id s1;

stack_id s2;

s1 = create_stack(200);

// ошибка забыли создатьS2

push(s1,’a’);

charc1 =pop(s1); // некрасивая запись

destroy_stack(s2);

// ошибка забыли уничтожитьs2

s1 =s2; // фактически присваивается указатель, кроме того,

// s2, используется после уничтожения

}

Другими словами, концепция модуля, которая поддерживает сокрытие данных, не поддерживает механизмы абстракции данных в полном объёме.

Такие языки как Ада, Clu, C++, разрешают эту проблему, позволяя пользователю определять типы, возможности работы с которыми почти те же, что и у основных типов. Такие типы часто называют абстрактными типами данных, хотя термин «типы, определяемые пользователем» или «пользовательские типы» является более точным: обоснованное определение абстрактного типа данных должно содержать «абстрактные» математические спецификации. То, что в С++ называется типами, на самом деле представляет собой конкретное воплощение подобных более абстрактных «сущностей». Парадигма программирования снова трансформируется.

«Определите, какие типы вам понадобятся; заготовьте полный набор операций для каждого типа».

Там же, где нет необходимости иметь более одного объекта каждого типа, достаточно модульного программирования.

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

В описании класса (то есть типа определяемого пользователем) complexсодержится формат представления комплексных чисел и набор операций над ними. Данные являются закрытыми или приватными.

Большинство, но, к сожалению, не все модули представляются как типы, определяемые пользователем.