Цель модульного программирования. Предназначение и принцип применения математического модуля. Языки поддерживающие данную парадигму

ТЕХНОЛОГИИ ПРОЕКТИРОВАНИЯ ПРОГРАММ

Введение

Структурное проектирование

Нисходящее проектирование

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

Структурное программирование

2. Объектно-ориентированное проектирование

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

2.2. Пример объектно-ориентированного проектирования

ЛИТЕРАТУРА

1. Марченко А.И. , Марченко Л.А. Программирование в среде Turbo Pascal 7.0. – 8-е изд. – К.: ВЕК+, СПб.: КОРОНА принт, 2004. с. 232-238.

2. Ставровский А.Б. Первые шаги в программировании. Самоучитель. – М.: «Вильямс», 2003. с. 113-133.

3. Вирт Н. Алгоритмы и структуры данных. – М.: Мир, 1989.

4. Иванова Г.С. Технология программирования : Учебник для вузов. – М.: Изд-во МГТУ им. Н.Э.Баумана, 2002. -320 с.

Введение

Промышленный подход к разработке программных продуктов породил ряд современных технологий проектирования алгоритмов и программ , среди которых наибольшее распространение получили:

· структурное проектирование программных продуктов;

· информационное моделирование предметной области

и связанных с ней приложений;

· объектно-ориентированное проектирование программных продуктов и др.

Целью данного занятия является изучение основных принципов структурного и объектно-ориентированного проектирования программ


Структурное проектирование

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

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

Типичными методами структурного проектирования являются:

· нисходящее проектирование, кодирование и тестирование программ;

· модульное программирование;

· структурное программирование и др.

В зависимости от объекта структурирования различают:

· функционально-ориентированные методы - последовательное разложение задачи или целостной проблемы на отдельные, достаточно простые составляющие, обладающие функциональной определенностью;

· методы структурирования данных .

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

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

Структурный подход использует:

· диаграммы потоков данных (информационно-технологические схемы) – показывают процессы и информационные потоки между ними с учетом событий, инициирующих процессы обработки;

· интегрированную структуру данных предметной области (инфологическая модель, ER-диаграммы);

· диаграммы декомпозиции – структура и декомпозиция целей, функций управления, приложений;

· структурные схемы – архитектура программного продукта в виде иерархии взаимосвязанных программных модулей с идентификацией связей между ними, детальная логика обработки данных программных модулей (блок-схемы).


Нисходящее проектирование

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

Спецификация задачи является ее первичным проектом . От него мы движемся к программе, постепенно уточняя описание.

Постепенное уточнение проектов широко используется во многих отраслях инженерной деятельности и называется методом проектирования сверху вниз (пошаговой детализации или нисходящего проектирования ).

В качестве примера рассмотрим проект одевания ребенка.

Первичная цель :

Конкретизация цели на первом шаге :

Одеть нижнюю половину.

Одеть верхнюю половину.

Нижнюю половину можно одеть в два этапа:

Надеть брюки.

Надеть носки и ботинки.

Верхнюю половину можно также одеть в два этапа:

Надеть рубашку.

Надеть куртку.

Окончательный проект выглядит так:

Надеть брюки.

Надеть носки.

Надеть ботинки.

Надеть рубашку.

Надеть куртку.

Метод нисходящего проектирования предполагает последовательное разложение общей функции обработки данных на простые функциональные элементы («сверху-вниз»). В результате строится иерархическая схема , отражающая состав и взаимоподчиненность отдельных функций, которая носит название функциональная структура алгоритма (ФСА ) (рис. 1.1).

Последовательность действий по разработке ФСА приложения следующая:

1) определяются цели автоматизации предметной области и их иерархия (цель-подцель);

2) устанавливается состав приложений (задач обработки), обеспечивающих реализацию поставленных целей;

3) уточняется характер взаимосвязи приложений и их основные характеристики (информация для решения задач, время и периодичность решения, условия выполнения и др.);

4) определяются необходимые для решения задач функции обработки данных ;

5)
выполняется декомпозиция функций обработки до необходимой структурной сложности, реализуемой предполагаемым инструментарием.

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

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

По частоте использования функции обработки делятся на:

· однократно выполняемые;

· повторяющиеся.

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

Уточнение действий при нисходящем проектировании - это, по сути, переход от описания того, что нужно сделать, к тому, как это сделать.

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

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

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

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

Модуль должен обладать следующими свойствами :

· один вход и один выход – на входе программный модуль получает определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор результатных данных, т.е. реализуется стандартный принцип IPO (Input - Process - Output - вход-процесс-выход );

· функциональная завершенность – модуль выполняет перечень регламентированных операций для реализации каждой отдельной функции в полном составе, достаточных для завершения начатой обработки;

· логическая независимость – результат работы программного модуля зависит только от исходных данных, но не зависит от работы других модулей;

· слабые информационные связи с другими программными модулями – обмен информацией между модулями должен быть по возможности минимизирован;

· обозримый по размеру и сложности программный код .

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

Каждый модуль состоит из спецификации и тела . Спецификации определяют правила использования модуля, а тело – способ реализации процесса обработки.

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

Однотипные функции реализуются одними и теми же модулями. Функция верхнего уровня обеспечивается главным модулем; он управляет выполнением нижестоящих функций, которым соответствуют подчиненные модули.

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

· каждый модуль вызывается на выполнение вышестоящим модулем и, закончив работу, возвращает управление вызвавшему его модулю;

· принятие основных решений в алгоритме выносится на максимально «высокий» по иерархии уровень;

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

В результате дальнейшей детализации алгоритма создается функционально-модульная схема (ФМС ) алгоритма приложения, являющася основой для программирования (рис. 1.2).

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

Алгоритмы большой сложности обычно представляются с помощью схем двух видов:

· обобщенной схемы алгоритма – раскрывает общий принцип функционирования алгоритма и основные логические связи между отдельными модулями на уровне обработки информации (ввод и редактирование данных, вычисления, печать результатов и т.п.);


Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

МИНОБРНАУКИ РОССИИ

Реферат

«Модульное программирование»

Введение

В основе того или иного языка программирования лежит некая руководящая идея, вызванная потребностями или, чаще всего, кризисом в области программирования и создания программного обеспечения, которая оказывает существенное влияние на стиль программирования и помогает преодолеть указанный кризис.

Машинно-ориентированное программирование появилось одновременно с созданием электронных вычислительных машин. Сначала это были программы в машинных кодах, затем появился язык программирования Assembler (Автокод), который немного «очеловечил» написание программы в машинном коде.

Процедурное программирование. Основная идея этого стиля - алгоритмизация процесса решения задачи и выбор наилучшего алгоритма (по расходу памяти или по быстродействию.

Структурное программирование. Здесь основная идея прекрасно выражена Н. Виртом в его книге "Алгоритмы + структуры данных = программы". Это был ответ на кризис в области программирования, начавшийся в середине 60-х годив, когда объем исходного программного кода перешел рубеж в 1000 строк. В 1971 году появился алгоритмический язык Pascal и немного позже, в 1972 году, язык С..

Модульное программирование. Здесь основная идея заключалась в том, чтобы "спрятать" данные и процедуры внутри независимых программных единиц - модулей. Эту идею впервые реализовал Н. Вирт в алгоритмическом языке Modula (1975-1979 годы), а затем "подхватили" и остальные, распространенные в то время языки программирования. Например, известные системы программирования Turbo Pascal и Turbo С.

Объектно-ориентированное программирование. С середины 80-х годов объем исходного программного кода перешел рубеж в 100 000 строк. Нужно было сделать не случайное объединение данных и алгоритмов их обработки в единое целое, а - смысловое. То есть необходимо было создать модульное программирование нового уровня, когда основной акцент делается на смысловую связь структур данных и алгоритмов их обработки

модуль программирование проектирование декомпозиция

1. Цель модульного программирования

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

Приступая к разработке каждой программы, следует иметь в виду, что она, как правило, является большой системой, поэтому надо принять меры для ее упрощения. Для этого такую программу разрабатывают по частям, которые называются программными модулями. А сам такой метод разработки программ называют модульным программированием. Программный модуль - это любой фрагмент описания процесса, оформляемый как самостоятельный программный продукт, пригодный для использования в описаниях процесса. Это означает, что каждый программный модуль программируется, компилируется и отлаживается отдельно от других модулей программы, и тем самым, физически разделен с другими модулями программы. Более того, каждый разработанный программный модуль может включаться в состав разных программ, если выполнены условия его использования, декларированные в документации по этому модулю. Таким образом, программный модуль может рассматриваться и как средство борьбы со сложностью программ, и как средство борьбы с дублированием в программировании (т.е. как средство накопления и многократного использования программистских знаний).

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

2. Основные характеристики программного модуля

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

Прочность модуля - это мера его внутренних связей. Чем выше прочность модуля, тем больше связей он может спрятать от внешней по отношению к нему части программы и, следовательно, тем больший вклад в упрощение программы он может внести. Для оценки степени прочности модуля Майерс предлагает упорядоченный по степени прочности набор из семи классов модулей. Самой слабой степенью прочности обладает модуль, прочный по совпадению . Это такой модуль, между элементами которого нет осмысленных связей. Такой модуль может быть выделен, например, при обнаружении в разных местах программы повторения одной и той же последовательности операторов, которая и оформляется в отдельный модуль. Необходимость изменения этой последовательности в одном из контекстов может привести к изменению этого модуля, что может сделать его использование в других контекстах ошибочным. Такой класс программных модулей не рекомендуется для использования.

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

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

Сцепление модуля - это мера его зависимости по данным от других модулей. Характеризуется способом передачи данных. Чем слабее сцепление модуля с другими модулями, тем сильнее его независимость от других модулей. Для оценки степени сцепления Майерс предлагает упорядоченный набор из шести видов сцепления модулей. Худшим видом сцепления модулей является сцепление по содержимому . Таким является сцепление двух модулей, когда один из них имеет прямые ссылки на содержимое другого модуля (например, на константу, содержащуюся в другом модуле). Такое сцепление модулей недопустимо. Не рекомендуется использовать также сцепление по общей области - это такое сцепление модулей, когда несколько модулей используют одну и ту же область памяти. Единственным видом сцепления модулей, который рекомендуется для использования современной технологией программирования, является параметрическое сцепление (сцепление по данным по Майерсу) - это случай, когда данные передаются модулю либо при обращении к нему как значения его параметров, либо как результат его обращения к другому модулю для вычисления некоторой функции. Такой вид сцепления модулей реализуется на языках программирования при использовании обращений к процедурам (функциям).

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

o всегда следует использовать рутинный модуль, если это не приводит к плохим (не рекомендуемым) сцеплениям модулей;

o зависящие от предыстории модули следует использовать только в случае, когда это необходимо для обеспечения параметрического сцепления;

o в спецификации зависящего от предыстории модуля должна быть четко сформулирована эта зависимость таким образом, чтобы было возможно прогнозировать поведение (эффект выполнения) данного модуля при разных последующих обращениях к нему.

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

3. Проектирование модуля

Модульное проектирование относится к процессу расчленения больших проблем на более узкие, более управляемые подпроблемы. Первым шагом проектирования является решение, в каком месте должна быть граница между этими подпроблемами.

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

3. 1 Функциональная декомпозиция

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

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

3.2 Минимизации количества передаваемых параметров

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

o В этом модуле предпринята попытка выполнения нескольких функций? Требует ли модуль параметры, используемые в не относящихся к данному модулю секциях? Если ответы на эти вопросы положительные, то необходимо снова обратиться к дальнейшей сегментации этого модуля.

o Модуль представляет собой функциональный разрез? Являются ли на самом деле вызывающий и вызываемый модули частью одной и той же функции? Если это так, то поместите их вместе в один модуль, даже если результирующий модуль окажется слишком большим. Затем попробуйте выполнить сегментацию модуля снова различными способами.

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

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

3.3 Минимизации количества необходимых вызовов

Одним из существенных преимуществ модульного программирования является то, что программа основного уровня очень часто может быть сконструирована для чтения как последовательность вызываемых процедур. Этот факт существенно повышает «понимаемость» программы, поскольку читатель может познакомиться с ее основным потоком и функционированием после прочтения только одной - двух страниц программного кода. Однако эта особенность может также иметь и недостатки. Одна из многих верхних статистических оценок программирования говорит о том, что 90% времени выполнения типовых программ расходуется в 10 % кода программы. При этом подразумевается, что если эти 10 % содержат большое количество цепочечных вызовов процедур, то суммарное время, затрачиваемое на управление выполнением программы, может стать непреодолимым препятствием на пути использования этого подхода.

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

Заключение

Большие программы обычно разрабатывают и отлаживают по частям. Целесообразно при этом, каждая такая часть, называемая подпрограммой, была оформлена так, чтобы ее можно было использовать при решении аналогичной подзадачи в той же программе или даже при решении других задач. В Borland Pascal реализованы два типа подпрограмм: процедуры и функции.

Модуль - это автономно компилируемая коллекция программных ресурсов, предназначенная для использования другими модулями и программами.

Все ресурсы модуля делятся на две группы: внешние - предназначенные для использования другими программными единицами, и внутренние - рабочие ресурсы данного модуля.

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

Размещено на Allbest.ru

Подобные документы

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

    реферат , добавлен 29.01.2016

    Характеристика модульного программирования: процедуры и функции, модули и их структура, открытые массивы и строки, нетипизированные параметры. Способы передачи параметров в подпрограммы в Borland Pascal. Объектно-ориентированное программирование.

    контрольная работа , добавлен 28.04.2009

    Сущность программирования с использованием среды Delphi 7 и ее основные графические возможности. Структура автономно компилируемого программного модуля и его принципы. Основные приемы работы с графическими процедурами, построение дуги, круга и эллипса.

    курсовая работа , добавлен 16.12.2011

    Появление первых вычислительных машин и возникновение "стихийного" программирования. Структурный подход к декомпозиции сложных систем. Развитие модульного и объектно-ориентированного программирования. Особенности компонентного подхода и CASE-технологий.

    презентация , добавлен 14.10.2013

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

    презентация , добавлен 05.11.2016

    Предмет исследования – современные методы разработки программ таких, как объектно-ориентированное программирование и визуальное проектирование, а также структурное и модульное программирование. C++ - универсальный язык программирования. Ключевые понятия.

    курсовая работа , добавлен 10.01.2009

    Почему C++. Возникновение и эволюция языка C++. Сравнение языков С++ и С. Эффективность и структура. Процедурное программирование. Модульное программирование. Абстракция данных. Объектно-ориентированное программирование. Улучшенный С.

    реферат , добавлен 03.06.2004

    Обзор технологий и систем геоинформационных систем. Системное и функциональное проектирование программного модуля, его разработка с использованием сред программирования Visual C++ 6.0, Qt 3.3.3. Технико-экономическое обоснование данного процесса.

    дипломная работа , добавлен 13.03.2011

    Проектирование программного модуля в среде программирования Borland Delphi 7.0. Схемы алгоритмов решения задач по темам "Символьные переменные и строки", "Массивы", "Работа с файлами", "Создание анимации". Реализация программного модуля, код программы.

    отчет по практике , добавлен 21.04.2012

    Проектирование информационной системы. Анализ языков программирования и существующих решений для администрирования системы управления базами данных. Разработка модуля взаимодействия и структуры программы. Модули авторизации и соединения с базой данных.

После того как начинающий embedder наморгается светодиодом, он непременно решит написать нечто более серьезное и у него как у любого начинающего будет только одно желание «чтобы всё быстрее заработало!!!». В такой попытке самоутвердиться он будет писать всё в один файл, не задумываясь о структуре программы, но через некоторое время, когда часть задуманного будет реализована, станет понятно, что чем больше становится программа, тем тяжелее в ней что-либо найти. Это натолкнет его на мысль, что у программы должна быть структура и он пойдёт на просторах интернета смотреть, как решают этот вопрос другие embedder"ы. Посмотрев, как выглядят программы, написанные другими людьми, он сделал вывод, что программу разбивают на файлы, которые представляют законченные логические единицы, что часть функции и переменных выносят в хэдер и ещё много чего. Всё вышеописанное - мой опыт, но все начинающие проходят один и тот же путь, поэтому опишу здесь, то с чем столкнулся сам.

Предположим у нас есть программа, которая выводит температуру на lcd дисплей и что для lcd дисплея, что для датчика температуры(ds18b20 ), нужна инициализация, а также функции для работы с ними. Поэтому логично будет создать два отдельных файла lcd.c и ds18b20.с , которые будут содержать в себе функции необходимые для работы. Такие файлы называют модулями , хотелось бы отметить, что каждый модуль представляет собой независимую, логически-завершенную единицу, которую можно компилировать отдельно от остальной программы . При компиляции модуля компилятор сделает из него объектный файл.

Следующий вопрос, который возникает, раз модуль это независимая структура, можно сказать «вещь в себе », то она не имеет связи с внешним миром, а нас это не устраивает. Для связи модулей с внешним миром используется заголовочные файлы, их также называют хэдерами/хидерами и они имеют расширение .h . Назвать хэдер можно как угодно, но удобнее, чтобы его название совпадало с названием модуля, lcd.h и ds18b20.h , также надо сказать, что все подключаемые файлы(#include ) удобно вынести в хэдер и подключать только его вначале модуля.
Когда хэдера не было, начало lcd.с выглядело так
#define F_CPU 8000000UL #include #include
а после создание хэдера стало выглядеть так
#include

Но тут же возникает еще один вопрос, что выносить в хэдер?
В хэдер необходимо вынести прототипы функций, которые могут понадобиться в других модулях программы . Прототип функции лишь объявляет функцию и не содержит тела функции, но посмотрев на него можно узнать имя функции, количество, тип аргументов и возвращаемый тип данных .
В файле lcd.h
void lcd_init(void); void lcd_write_symbol(char symbol); void lcd_write_string(char *str); void lcd_clear(void);
В файле ds18b20.h будут объявлены следующие прототипы:
void ds18b20_init(void); uint8_t ds18b20_get_temperature(void);

Что касается макросов, можно вынести макросы, отвечающие за выполнение условной компиляции
#define MAKE_CALIBRATION //раскомментировать для калибровки
А где-то в коде есть конструкция, которая выполняется если предыдущая строчка раскомментирована
#ifdef MAKE_CALIBRATION touch_x -= 300; touch_x = 240 - touch_x/((Xmax-Xmin)/240); touch_y -= 350; touch_y = 320 - touch_y/((Ymax-Ymin)/320); #endif
Также можно вынести макросы, отвечающие за выбор выводов, к которым будет подключаться периферия
#define D0 PORTA //так данные передаются по 16 битной шине, #define D7 PORTD //под это дело мы используем два порта

Но в то же время в хэдере не надо размещать то, что не понадобится в других модулях:

  • макросы типа
    #define (LCD_PIN & 0X80) check_busy_flag
  • переменные, которые будут использоваться только внутри модуля с ключевым словом static
  • переменные с квалификатором extern
  • прототипы функций, которые нужны для каких-то промежуточных действий, например, функцию, которая переводит число в BCD формат

Теперь пару слов про подключение хэдеров, при программировании микроконтроллеров AVR почти во всех модулях подключается хэдер для работы с портами ввода-вывода.
#include avr/io.h
То есть он подключается в lcd.h и в ds18b20.h , теперь если мы подключим эти два заголовка в основном файле программы, то avr/io.h подключится дважды, хотя достаточно было и одного . Для того чтобы избежать возникновения такой ситуации и хэдер не подключился дважды используют #include guards , который выглядит следующим образом.
#ifndef _ENCODER_H_ #define _ENCODER_H_ // оформляем как обычный хэдер #endif
Это конструкция позволяет препроцессору определить, что данный хэдер уже включался в программу и не включать его повторно. Подробнее про это можно почитать .
Также ограничить количество подключений файла до одного, можно с помощью конструкции
#pragma once // оформляем как обычный хэдер
Преимущество использование #pragma once вместо #include guards можно почитать .
Кстати подключать можно не только хэдеры, а также файлы с расширением , если это надо
#include “font.c”
В данном случае для вывода букв на TFT дисплей подключается файл с шрифтами.
На этом всё, мне кажется это минимум, который необходимо знать каждому начинающему программисту микроконтроллеров.

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

Концепции модульного программирования. В основе модульного программирования лежат три основных концепции:

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

Аксиома модульности Коуэна. Модуль - независимая программная единица, служащая для выполнения некоторой определенной функции программы и для связи с остальной частью программы. Программная единица должна удовлетворять следующим условиям:

· блочность организации, т. е. возможность вызвать программную единицу из блоков любой степени вложенности;

· синтаксическая обособленность, т. е. выделение модуля в тексте синтаксическими элементами;

· семантическая независимость, т. е. независимость от места, где программная единица вызвана;

· общность данных, т. е. наличие собственных данных, сохраняющихся при каждом обращении;

· полнота определения, т. е. самостоятельность программной единицы.

Сборочное программирование Цейтина. Модули - это программные кирпичи, из которых строится программа. Существуют три основные предпосылки к модульному программированию:

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

· потребность организационного расчленения крупных разработок;

· возможность параллельного исполнения модулей (в контексте параллельного программирования).

Определения модуля и его примеры. Приведем несколько дополнительных определений модуля.

· Модуль - это совокупность команд, к которым можно обратиться по имени.

· Модуль - это совокупность операторов программы, имеющая граничные элементы и идентификатор (возможно агрегатный).

Функциональная спецификация модуля должна включать:

· синтаксическую спецификацию его входов, которая должна позволять построить на используемом языке программирования синтаксически правильное обращение к нему;

· описание семантики функций, выполняемых модулем по каждому из его входов.

Разновидности модулей. Существуют три основные разновидности модулей:

1) "Маленькие" (функциональные) модули, реализующие, как правило, одну какую-либо определенную функцию. Основным и простейшим модулем практически во всех языках программирования является процедура или функция.

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

a)задачи в языке программирования Ada;

b)кластер в языке программирования CLU;

c)классы в языках программирования C++ и Java.

3) "Большие” (логические) модули , объединяющие набор "средних" или "маленьких" модулей. Примеры "больших" модулей в языках программирования:

a)модуль в языке программирования Modula-2;

b)пакеты в языках программирования Ada и Java.

Набор характеристик модуля предложен Майерсом [Майерс 1980]. Он состоит из следующих конструктивных характеристик:

1) размера модуля;

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

Модуль (функция) не должен превышать 60 строк. В результате его можно поместить на одну страницу распечатки или легко просмотреть на экране монитора.

2) прочности (связности) модуля;

Существует гипотеза о глобальных данных, утверждающая, что глобальные данные вредны и опасны. Идея глобальных данных дискредитирует себя так же, как и идея оператора безусловного перехода goto. Локальность данных дает возможность легко читать и понимать модули, а также легко удалять их из программы.

Связность (прочность) модуля (cohesion) - мера независимости его частей. Чем выше связность модуля - тем лучше, тем больше связей по отношению к оставшейся части программы он упрятывает в себе. Можно выделить типы связности, приведенные ниже.

Функциональная связность. Модуль с функциональной связностью реализует одну какую-либо определенную функцию и не может быть разбит на 2 модуля с теми же типами связностей.

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

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

Обратим внимание на то, что средства для задания информационно прочных модулей отсутствовали в ранних языках программирования (например, FORTRAN и даже в оригинальной версии языка Pascal). И только позже, в языке программирования Ada, появился пакет - средство задания информационно прочного модуля.

3) сцепления модуля с другими модулями;

Сцепление (coupling) - мера относительной независимости модуля от других модулей. Независимые модули могут быть модифицированы без переделки других модулей. Чем слабее сцепление модуля, тем лучше. Рассмотрим различные типы сцепления.

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

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

· Сцепление по простым элементам данных.

· Сцепление по структуре данных. В этом случае оба модуля должны знать о внутренней структуре данных.

4) рутинности (идемпотентность, независимость от предыдущих обращений) модуля.

Рутинность - это независимость модуля от предыдущих обращений к нему (от предыстории). Будем называть модуль рутинным, если результат его работы зависит только от количества переданных параметров (а не от количества обращений).

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

· В большинстве случаев делаем модуль рутинным, т. е. независимым от предыдущих обращений.

· Зависящие от предыстории модули следует использовать только в тех случаях, когда это необходимо для сцепления по данным.

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

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

Как уже упоминалось раньше, в настоящее время используют два спосо­ба декомпозиции разрабатываемого программного обеспечения, связанные с соответствующим подходом:

Процедурный (или структурный - по названию подхода);

Объектный.

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

Результатом объектной декомпозиции является совокупность объектов, которые затем реализуют как переменные некоторых специально разрабаты­ваемых типов (классов), представляющих собой совокупность полей данных и методов, работающих с этими полями.

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

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

Данные модуль может получать и/или возвращать через общие области памяти или параметры.

Первоначально к модулям (еще понимаемым как подпрограммы) предъ­являлись следующие требования:

Отдельная компиляция;

Одна точка входа;

Одна точка выхода;

Соответствие принципу вертикального управления;

Возможность вызова других модулей;

Небольшой размер (до 50-60 операторов языка);

Независимость от истории вызовов;

Выполнение одной функции.

Требования одной точки входа, одной точки выхода, независимости от истории вызовов и соответствия принципу вертикального управления были вызваны тем, что в то время из-за серьезных ограничений на объем опера­тивной памяти программисты были вынуждены разрабатывать программы с максимально возможной повторяемостью кодов. В результате подпрограм­мы, имеющие несколько точек входа и выхода, были не только обычным яв­лением, но и считались высоким классом программирования. Следствием же было то, что программы было очень сложно не только модифицировать, но и понять, а иногда и просто полностью отладить.



Со временем, когда основные требования структурного подхода стали поддерживаться языками программирования, и под модулем стали понимать

отдельно компилируемую библиотеку ресурсов, требование независимости модулей стало основным.

Практика показала, что чем выше степень независимости модулей, тем:

Легче разобраться в отдельном модуле и всей программе и, соответственно, тестировать, отлаживать и модифицировать ее;

Меньше вероятность появления новых ошибок при исправлении ста­рых или внесении изменений в программу, т. е. вероятность появления «волнового» эффекта;

Проще организовать разработку программного обеспечения группой программистов и легче его сопровождать.

Таким образом, уменьшение зависимости модулей улучшает техноло­гичность проекта. Степень независимости модулей (как подпрограмм, так и библиотек) оценивают двумя критериями: сцеплением и связностью.

Сцепление модулей. Сцепление является мерой взаимозависимости мо­дулей, которая определяет, насколько хорошо модули отделены друг от дру­га. Модули независимы, если каждый из них не содержит о другом никакой информации. Чем больше информации о других модулях хранит модуль, тем больше он с ними сцеплен.

Различают пять типов сцепления модулей:

По данным;

По образцу;

По управлению;

По общей области данных;

По содержимому.

Сцепление по данным предполагает, что модули обмениваются данны­ми, представленными скалярными значениями. При небольшом количестве передаваемых параметров, этот тип обеспечивает наилучшие технологичес­кие характеристики программного обеспечения.

Например, функция Мах предполагает сцепление по данным через па­раметры скалярного типа:

Function Max(a, b: integer) : integer;

If a>b then Max:=a else Max: =b;

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

Так, функция MaxEl, описанная ниже, предполагает сцепление по образ­цу (параметр а - открытый массив).

Function MaxEl(a:array of integer):integer;

Var i:word;

MaxEl:=a;

for i:=l to High(a) do

if a[i]>MaxEl then MaxEl: =a[i];

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

Например, функция MinMax предполагает сцепление по управлению, так как значение параметра flag влияет на логику программы: если функция MinMax получает значение параметра flag, равное true, то возвращает макси­мальное значение из двух, а если false, то минимальное:

Function MinMax(a, b: integer; flag: boolean): integer;

if(a>b) and (flag) then MinMax: =a

else MinMax: =b;

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

Программы, использующие данный тип сцепления, очень сложны для понимания при сопровождении программного обеспечения;

Ошибка одного модуля, приводящая к изменению общих данных, мо­жет проявиться при выполнении другого модуля, что существенно усложня­ет локализацию ошибок;

Например, функция МахА, использующая глобальный массив А, сцеп­лена с основной программой по общей области:

Function MaxA:integer; Var i:word;

MaxA: =a; for i:= Low(a)+l to High(a) do if a[i]>MaxA then MaxA: =a[i];

Следует иметь в виду, что «подпрограммы с памятью», действия кото­рых зависят от истории вызовов, используют сцепление по общей области, что делает их работу в общем случае непредсказуемой. Именно этот вариант используют статические переменные С и C++.

В случае сцепления по содержимому один модуль содержит обращения к внутренним компонентам другого (передает управление внутрь, читает и/или изменяет внутренние данные или сами коды), что полностью противо­речит блочно-иерархическому подходу. Отдельный модуль в этом случае уже не является блоком («черным ящиком»): его содержимое должно учитывать­ся в процессе разработки другого модуля. Современные универсальные язы­ки процедурного программирования, например Pascal, данного типа сцепле­ния в явном виде не поддерживают, но для языков низкого уровня, например Ассемблера, такой вид сцепления остается возможным.

В табл. 2.1 приведены характеристики различных типов сцепления по экспертным оценкам . Допустимыми считают первые три типа сцеп­ления, так как использование остальных приводит к резкому ухудшению тех­нологичности программ.

Как правило, модули сцепляются между собой несколькими способами. Учитывая это, качество программного обеспечения принято определять по типу сцепления с худшими характеристиками. Так, если использовано сцеп­ление по данным и сцепление по управлению, то определяющим считают сцепление по управлению.

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

Связность модулей. Связность - мера прочности соединения функци­ональных и информационных объектов внутри одного модуля. Если сцепле­ние характеризует качество отделения модулей, то связность характеризует степень взаимосвязи элементов, реализуемых одним модулем. Размещение сильно связанных элементов в одном; модуле уменьшает межмодульные свя­зи и, соответственно, взаимовлияние модулей. В то же время помещение сильно связанных элементов в разные модули не только усиливает межмо­дульные связи, но и усложняет понимание их взаимодействия. Объединение слабо связанных элементов также уменьшает технологичность модулей, так как такими элементами сложнее мысленно манипулировать.

Различают следующие виды связности (в порядке убывания уровня):

Функциональную;

Последовательную;

Информационную (коммуникативную);

Процедурную;

Временную;

Логическую;

Случайную.

При функциональной связности все объекты модуля предназначены для выполнения одной функции (рис. 2.1, а): операции, объединяемые для вы­полнения одной функции, или.данные, связанные с одной функцией. Модуль, элементы которого связаны функционально, имеет четко определенную цель, при его вызове выполняется одна задача, например, подпрограмма по­иска минимального элемента массива. Такой модуль имеет максимальную связность, следствием которой являются его хорошие технологические каче­ства: простота тестирования, модификации и сопровождения. Именно с этим связано одно из требований структурной декомпозиции «один модуль - одна функция».

Из тех же соображений следует избегать неструктурированного распре­деления функции между модулями - библиотеками ресурсов. Например, ес­ли при проектировании текстового редактора предполагается функция редактирования, то лучше организовать модуль - библиотеку функций редактиро­вания, чем поместить часть функций в один модуль, а часть в другой.

При последовательной связности функций выход одной функции слу­жит исходными данными для другой функции (рис. 2.1, б). Как правило, та­кой модуль имеет одну точку входа, т. е. реализует одну подпрограмму, вы­полняющую две функции. Считают, что данные, используемые последова­тельными функциями, также связаны последовательно. Модуль с последова­тельной связностью функций можно разбить на два или более модулей, как с последовательной, так и с функциональной связностью. Такой модуль вы­полняет несколько функций, и, следовательно, его технологичность хуже: сложнее организовать тестирование, а при выполнении модификации мыс­ленно приходится разделять функции модуля,

Информационно связанными считают функции, обрабатывающие одни и те же данные (рис. 2.1, в). При использовании структурных языков програм­мирования раздельное выполнение функций можно осуществить только, ес­ли каждая функция реализуется своей подпрограммой. Хотя раньше в подоб­ных случаях обычно использовали разные точки входа в модуль, оформлен­ный как одна подпрограмма.

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

Процедурно связаны функции или данные, которые являются частями одного процесса (рис. 2.1, г). Обычно модули с процедурной связностью функций получают, если в модуле объединены функции альтернативных ча­стей программы. При процедурной связности отдельные элементы модуля связаны крайне слабо, так как реализуемые ими действия связаны лишь об­щим процессом, следовательно, технологичность данного вида связи ниже, чем предыдущего.

Временная связность функций подразумевает, что эти функции выпол­няются параллельно или в течение некоторого периода времени (рис. 2.1, д). Временная связность данных означает, что они используются в некотором временном интервале. Например, временную связность имеют функции, вы­полняемые при инициализации некоторого процесса. Отличительной осо­бенностью временной связности является то, что действия, реализуемые та­кими функциями, обычно могут выполняться в любом порядке. Содержание модуля с временной связностью функций имеет тенденцию меняться: в него могут включаться новые действия и/или исключаться старые. Большая веро­ятность модификации функции еще больше уменьшает показатели техноло­гичности модулей данного вида по сравнению с предыдущим.

Логическая связь базируется на объединении данных или функций в од­ну логическую группу (рис. 2.1, е). В качестве примера можно привести функции обработки текстовой информации или данные одного и того же ти­па. Модуль с логической связностью функций часто реализует альтернатив­ные варианты одной операции, например, сложение целых чисел и сложение вещественных чисел. Из такого модуля всегда будет вызываться одна какая-либо его часть, при этом вызывающий и вызываемый модули будут связаны по управлению. Понять логику работы модулей, содержащих логически свя­занные компоненты, как правило, сложнее, чем модулей, использующих вре­менную связность, следовательно их показатели технологичности еще ниже.

В том случае, если связь между элементами мала или отсутствует, счи­тают, что они имеют случайную связность. Модуль, элементы которого свя­заны случайно, имеет самые низкие показатели технологичности, так как элементы, объединенные в нем, вообще не связаны.

Обратите внимание, что в трех предпоследних случаях связь между не­сколькими подпрограммами в модуле обусловлена внешними причинами. А в последнем - вообще отсутствует. Это соответствующим образом проециру­ется на технологические характеристики модулей. В табл. 2.2 представлены характеристики различных видов связности по экспертным оценкам .

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

Как правило, при хорошо продуманной декомпозиции модули верхних уровней иерархии имеют функциональную или последовательную связность функций и данных. Для модулей обслуживания данных характерна информа­ционная связность функций. Данные таких модулей могут быть связаны по-разному. Так, модули, содержащие описание классов при объектно-ориенти­рованном подходе, характеризуются информационной связностью методов и функциональной связностью данных. Получение в процессе декомпозиции модулей с другими видами связности, скорее всего, означает недостаточно продуманное проектирование. Исключением являются лишь библиотеки ре­сурсов.

Библиотеки ресурсов. Различают библиотеки ресурсов двух типов: библиотеки Подпрограмм и библиотеки классов.

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

Библиотеки классов реализуют близкие по назначению.классы. Связ­ность элементов класса - информационная, связность классов между собой может быть функциональной - для родственных или ассоциированных клас­сов и логической - для остальных.

В качестве средства улучшения технологических характеристик библи­отек ресурсов в настоящее время широко используют разделение тела моду­ля на интерфейсную часть и область реализации (секции Interface и Imple­mentation - в Pascal, h и срр-файлы в C++ и в Java).

Интерфейсная часть в данном случае содержит совокупность объявле­ний ресурсов (заголовков подпрограмм, имен переменных, типов, классов и т. п.), которые данная библиотека предоставляет другим модулям. Ресурсы, объявление которых в интерфейсной части отсутствует, извне не доступны.

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