Другое: Технология программирования

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

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

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

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

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

достижимость модуля - наличие всех модулей в цепочке вызова данного модуля;

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

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

наличие необходимых ресурсов.

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

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

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

Нисходящий подход обеспечивает:

максимально полное определение спецификаций проектируемого компонента и согласованность компонентов между собой;

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

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

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

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

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


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

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

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

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

Именно для изображения схем алгоритмов таких программ в свое время был разработан ГОСТ 19.701-90, согласно которому каждой группе действий ставится в соответствие специальный блок (табл. 1 .1). Хотя этот стандарт предусматривает блоки для обозначения циклов, он не запрещает и произвольной передачи управления, т. е. допускает использование команд условной и безусловной передачи управления при реализации алгоритма.

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

следование - обозначает последовательное выполнение действий (рис. 2.3, а);

ветвление - соответствует выбору одного из двух вариантов действий (рис. 2.3, б);

цикл-пока - определяет повторение действий, пока не будет нарушено некоторое условие, выполнение которого проверяется в начале цикла (рис. 2.3, в).

Рисунок 2.1-Базовые алгоритмические структуры:

а- следование, б- ветвление, цикл-пока

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

выбор - обозначает выбор одного варианта из нескольких в зависимости от значения некоторой величины (рис. 2.4, а);

цикл-до - обозначает повторение некоторых действий до выполнения заданного условия, проверка которого осуществляется после выполнения действий в цикле (рис. 2.4, б);

цикл с заданным числом повторений (счетный цикл) - обозначает повторение некоторых действий указанное количество раз (рис. 2.4, в).

Рисунок 2.2- Дополнительные структуры алгоритмов: а- выбор, б- цикл-до, в- цикл с заданным числом повторений.

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

Примечание. Слово "структурное" в данном названии подчеркивает тот факт, что при программировании использованы только перечисленные конструкции (структуры). Отсюда и понятие "программирование без go to".

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

Модули и их свойства

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

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

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

6объектный.

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

10по данным;

11по образцу;

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

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

14по содержимому.

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

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

Function Max(a, b: integer).'integer; begina>b then Max:=a else Max:=b; end;

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

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

Function MaxEl(a:array of integer).'integer; Var i:word; begin: =a[OJ;i:=l to High(a) doa[i]>MaxEl then MaxEl:=afij;

end;

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

Function MinMax(a, b:integer;jlag:boolean):integer; begin(a>b) and (flag) then MinMax: =a

else MinMax: =6; end;

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

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

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

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

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

информационный компьютеризация программа файл

Function MaxA: integer; Var i:word; begin

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

end;

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

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

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

Источник: https://www.bibliofond.ru/detail.aspx?id=786582