3. Структурное программирование
Сутью структурного программирования является возможность разбиения программы на составляющие элементы. Идеи структурного программирования появились в начале 70-годов в компании IBM, в их разработке участвовали известные ученые Э. Дейкстра, Х. Милс, Э. Кнут, С. Хоор. Распространены две методики (стратегии) разработки программ, относящиеся к структурному программированию: программирование «сверху вниз» и программирование «снизу вверх». Программирование «сверху вниз», или нисходящее программирование – это методика разработки программ, при которой разработка начинается с определения целей решения проблемы, после чего идет последовательная детализация, заканчивающаяся детальной программой. Является противоположной методике программирования «снизу вверх». При нисходящем проектировании задача анализируется с целью определения возможности разбиения ее на ряд подзадач. Затем каждая из полученных подзадач также анализируется для возможного разбиения на подзадачи. Процесс заканчивается, когда подзадачу невозможно или нецелесообразно далее разбивать на подзадачи. В данном случае программа конструируется иерархически — сверху вниз: от главной программы к подпрограммам самого нижнего уровня, причем на каждом уровне используются только простые последовательности инструкций, циклы и условные разветвления. Программирование «снизу вверх», или восходящее программирование – это методика разработки программ, начинающаяся с разработки подпрограмм (процедур, функций), в то время когда проработка общей схемы не закончилась. Является противоположной методике программирования «сверху вниз». Такая методика является менее предпочтительной по сравнению с нисходящим программированием, так как часто приводит к нежелательным результатам, переделкам и увеличению времени разработки. Рассмотрим следующий пример. Разработать программный комплекс, который рисует на экране дисплея дачный участок, состоящий из дороги, забора, елки и сияющего на небе солнца. Нарисованная картина показана на рис. 1. Рис. 1. Дачный участок. Укажем в виде схем, которые называются структурными диаграммами, составные элементы картины: Посмотрим на изображение дома. Здесь можно выделить следующие элементы:Дальнейшая детализация стены, крыши, двери, окна, трубы, дороги, забора и солнца нецелесообразна. Елка состоит из двух элементов:Если объединить все приведенные структурные диаграммы, то получим первый вариант изображения структурной диаграммы программного комплекса, показанный на рис. 2.Рис. 2. Структурная диаграмма (первый вариант) Второй вариант представления структурной диаграммы имеет вид, представленный на рис. 3.Рис. 3. Структурная диаграмма (второй вариант) На рис. 2 и рис. 3 отмечены уровни, занимаемые программными модулями. Каждый нижележащий уровень соответствует более полной детализации программного комплекса. Те модули, которые не имеют дальнейшей детализации, например, «солнце», «ствол», «стена», являются процедурами, или функциями, реализующими решение соответствующей подзадачи. Разбиение программы на модули представляет одну из достаточно ответственных и сложных задач, так как влияет на дальнейший ход разработки программного комплекса, его надёжность, эффективность, продолжительность тестирования и отладки, сопровождение и возможность использование стандартных программных процедур. Достоинства структурного программирования: 1) повышается надежность программ (благодаря хорошему структурированию при проектировании, программа легко поддается тестированию и не создает проблем при отладке); 2) повышается эффективность программ (структурирование программы позволяет легко находить и корректировать ошибки, а отдельные подпрограммы можно переделывать (модифицировать) независимо от других); 3) уменьшается время и стоимость программной разработки; 4) улучшается читабельность программ. Резюме Технология структурного программирования при разработке серьезных программных комплексов, основана на следующих принципах: — программирование должно осуществляться сверху вниз; — весь проект должен быть разбит на модули (подпрограммы) с одним входом и одним выходом; — подпрограмма должна допускать только три основные структуры – последовательное выполнение, ветвление (if, case) и повторение (for, while, repeat). — недопустим оператор передачи управления в любую точку программы (goto); — документация должна создаваться одновременно с программированием в виде комментариев к программе. Структурное программирование эффективно используется для решения различных задач, имеющих алгоритмический характер.
8.2. Структурное программирование.
При программировании модуля следует иметь ввиду, что программа должна быть понятной не только компьютеру, но и человеку: и разработчик модуля, и лица, проверяющие модуль, и тестовики, готовящие тесты для отладки модуля, и сопроводители ПС, осуществляющие требуемые изменения модуля, вынуждены будут многократно разбирать логику работы модуля. В современных языках программирования достаточно средств, чтобы запутать эту логику сколь угодно сильно, тем самым, сделать модуль трудно понимаемым для человека и, как следствие этого, сделать его ненадежным или трудно сопровождаемым. Поэтому необходимо принимать меры для выбора подходящих языковых средств и следовать определенной дисциплине программирования. Впервые на это обратил внимание Дейкстра [8.2] и предложил строить программу как композицию из нескольких типов управляющих конструкций (структур), которые позволяют сильно повысить понимаемость логики работы программы. Программирование с использованием только таких конструкций назвали структурным.
Рис. 8.1. Основные управляющие конструкции структурного программирования.
Основными конструкциями структурного программирования являются: следование, разветвление и повторение (см. Рис. 8.1). Компонентами этих конструкций являются обобщенные операторы (узлы обработки [8.5]) S, S1, S2 и условие (предикат) P. В качестве
обобщенного оператора может быть либо простой оператор используемого языка программирования (операторы присваивания, ввода, вывода, обращения к процедуре), либо фрагмент программы, являющийся композицией основных управляющих конструкций структурного программирования. Существенно, что каждая из этих конструкций имеет по управлению только один вход и один выход. Тем самым, и обобщенный оператор имеет только один вход и один выход.
Весьма важно также, что эти конструкции являются уже математическими объектами (что, по-существу, и объясняет причину успеха структурного программирования). Доказано, что для каждой неструктурированной программы можно построить функционально эквивалентную (т.е. решающую ту же задачу) структурированную программу. Для структурированных программ можно математически доказывать некоторые свойства, что позволяет обнаруживать в программе некоторые ошибки. Этому вопросу будет посвящена отдельная лекция.
Структурное программирование иногда называют еще «программированием без GO TO». Однако дело здесь не в операторе GO TO, а в его беспорядочном использовании. Очень часто при воплощении структурного программирования на некоторых языках программирования (например, на ФОРТРАНе) оператор перехода (GO TO) используется для реализации структурных конструкций, не снижая основных достоинств структурного программирования. Запутывают программу как раз «неструктурные» операторы перехода, особенно переход на оператор, расположенный в тексте модуля выше (раньше) выполняемого оператора перехода. Тем не менее, попытка избежать оператора перехода в некоторых простых случаях может привести к слишком громоздким структурированным программам, что не улучшает их ясность и содержит опасность появления в тексте модуля дополнительных ошибок. Поэтому можно рекомендовать избегать употребления оператора перехода всюду, где это возможно, но не ценой ясности программы [8.1].
К полезным случаям использования оператора перехода можно отнести выход из цикла или процедуры по особому условию, «досрочно» прекращающего работу данного цикла или данной процедуры, т.е. завершающего работу некоторой структурной единицы (обобщенного оператора) и тем самым лишь локально нарушающего структурированность программы. Большие трудности (и усложнение структуры) вызывает структурная реализация реакции на возникающие исключительные (часто ошибочные) ситуации, так как при этом требуется не только осуществить досрочный выход из структурной единицы, но и произвести необходимую обработку (исключение) этой ситуации (например, выдачу подходящей диагностической информации). Обработчик исключительной ситуации может находиться на любом уровне структуры программы, а обращение к нему может производиться с разных нижних уровней. Вполне приемлемой с технологической точки зрения является следующая «неструктурная» реализация реакции на исключительные ситуации [8.7]. Обработчики исключительных ситуаций помещаются в конце той или иной структурной единицы и каждый такой обработчик программируется таким образом, что после окончания своей работы производит выход из той структурной единицы, в конце которой он помещен. Обращение к такому обработчику производится оператором перехода из данной структурной единицы (включая любую вложенную в нее структурную единицу).