Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии и методы программирования. Учебное пособие-1

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
как лямбда-выражения и вывод типов, поддерживают функциональный стиль программирования.
К императивной парадигме обычно относят структурное програм­мирование, процедурное программирование, объектно-ориентирован­ное программирование.
ОСНОВЫ СТРУКТУРНОГО ПРОГРАММИРОВАНИЯ
Структурное программирование – это использование определен­ных принципов и правил проектирования, разработки и оформления программ с целью облегчения процессов их создания и тестирования, повышения производительности труда программистов и улучшения чи­табельности результирующей программы. Структура программы и ал­горитм решения задачи должны быть легкими для понимания, про­стыми для доказательства правильности и
удобными для модификации. По своей сути структурный подход есть отказ от беспорядочного стиля в алгоритмизации и программировании (в частности отказ от оператора goto [16], недопущение так называемых спагетти-программ [53]) и опре­деление ограниченного числа стандартных приемов построения легко читаемых алгоритмов и программ с ясно выраженной структурой, что особенно важно при разработке больших
программных систем.
Структурное программирование предполагает определенную орга­низацию самого процесса программирования и технологию проектиро­вания программ, что также положительно влияет на производитель­ность труда программистов.
Теоретическим фундаментом структурного программирования яв­ляется теорема о структурировании (теорема Бема–Якопини) [54], из ко­торой следует, что алгоритм (программа) решения любой практически вычислимой задачи может
быть представлен с использованием трех эле­ментарных базисных управляющих структур: структуры следования (последовательности); структуры ветвления, структуры цикла, изобра­женных на рис. 8.
Структура следования представляет собой естественный ход вы­полнения алгоритма – любую последовательность операторов, выпол­няющихся друг за другом (рис. 8, а).
Структура ветвления представляет блок принятия решения, включает проверку некоторого логического
сти от результатов этой проверки, выполнение оператора
S
оператора
(рис. 8, б).
2
условия Р и, в зависимо-
S
либо
1
41
а б в где Русловие; S – оператор.
Рис. 8. Элементарные базисные управляющие структуры
Структура цикла (цикла с предусловием) представляет фактор по-
вторяемости вычислений, обеспечивает многократное повторение вы­полнения оператора S, пока выполняется (истинно) логическое условие (рис. 8, в).
Базисный набор управляющих структур является функционально полным, т. е. с его помощью можно описать любой сколь угодно слож­ный алгоритм, однако с целью создания более компактных
и наглядных алгоритмов и программ используются дополнительные управляющие структуры: структура сокращенного ветвления; структура варианта, или многоальтернативного выбора; структура цикла со счетчиком; струк­тура цикла с постусловием.
Для структурирования и понимания больших по объему программ используются также дополнительные структурные средства, которые поддерживают модульный принцип разработки ПС: это подпрограммы и модули. Использование механизма
подпрограмм (процедур и функ-
ций) – это возможность выделять в самостоятельные программные еди-
ницы со своими входными и выходными данными отдельные (часто по­вторяющиеся) участки кода для последующего многократного вызова их из различных точек программы и других подпрограмм.
Модуль представляет собой автономно компилируемую библио- теку описаний типов, данных, процедур и
функций, что позволяет груп­пировать описания данных и подпрограмм по их функциям и назначе­нию согласно одному из основных принципов структурного програм­мирования – разбиению больших задач на подзадачи.
42
ПРИНЦИПЫ СТРУКТУРНОГО ПРОГРАММИРОВАНИЯ
Становление и развитие структурного программирования связано
с именем Эдсгера Дейкстры [16].
Принцип 1. Следует отказаться от использования оператора без-
условного перехода goto.
Принцип 2. Любая программа строится из трех базовых управляю-
щих конструкций: последовательности, ветвления, цикла.
Последовательность – однократное выполнение операций в том по-
рядке, в котором они записаны в тексте программы. Бертран Мейер
по­ясняет: «Последовательное соединение: используйте выход одного эле­мента как вход к другому, подобно тому как электрики соединяют вы­ход сопротивления со входом конденсатора» [17].
Ветвление – однократное выполнение одной из двух или более опе-
раций, в зависимости от выполнения заданного условия.
Цикл – многократное исполнение одной и той же операции до тех
пор
, пока выполняется заданное условие (условие продолжения цикла).
Принцип 3. В программе базовые управляющие конструкции могут быть вложены друг в друга произвольным образом. Никаких других средств управления последовательностью выполнения операций не предусматривается.
Принцип 4. Повторяющиеся фрагменты программы можно офор­мить в виде подпрограмм (процедур и функций). Таким же образом
(в виде подпрограмм
) можно оформить логически целостные фраг-
менты программы, даже если они не повторяются. Бертран Мейер [55] поясняет: «Преобразуйте элемент, возможно, с внутренними элемен­тами, в подпрограмму, характеризуемую одним входом и одним выхо­дом в потоке управления».
Принцип 5. Каждую логически законченную группу инструкций следует оформить как блок. Блоки являются основой структурного про­граммирования
.
Блок – это логически сгруппированная часть исходного кода, напри­мер набор инструкций, записанных подряд в исходном коде программы. Понятие «блок» означает, что к блоку инструкций следует обращаться как к единой инструкции. Блоки служат для ограничения области види­мости переменных и функций. Блоки могут быть пустыми или вложен­ными один в другой.
Границы блока строго определены. Например, в if-инструкции блок ограничен кодом BEGIN..END (в языке Pascal) или фигурными скобками {...} (в языке C++, С#) или отступами (в языке
Python).
43
Принцип 6. Все перечисленные конструкции должны иметь один
вход и один выход.
Ограничение управляющими конструкциями с одним входом и од­ним выходом дает возможность построить произвольные алгоритмы любой сложности с помощью простых и надежных механизмов.
Принцип 7. Разработка программы ведется пошагово, методом «сверху вниз» [5].
ПРОЦЕДУРНОЕ ПРОГРАММИРОВАНИЕ
Процедурное программирование – парадигма программирования, основанная на алгоритмической (процедурной) декомпозиции и кон­цепции вызова процедуры. Процедурная декомпозиция состоит в том, что задача, реализуемая программой, разделяется на подзадачи, а они в свою очередь – на более мелкие этапы, т. е. выполняется пошаговая детализация алгоритма решения задачи. Процедуры (подпрограммы, методы, функции) содержат последовательность команд (операторов для выполнения. В ходе выполнения программы любая процедура мо­жет быть вызвана из любой точки, включая саму данную процедуру (ре­курсивный вызов).
Процедурное программирование широко используется в крупномас­штабных проектах, когда на первый план выходят следующие преиму­щества:
возможность поддержки модульности и структурности;
легкость повторного использования фрагментов кода,
оформлен-
ных как процедуры (например, в библиотеках);
легкость прослеживания логики программы, что облегчает тести- рование, отладку и сопровождение.
)
МОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ
По мере усложнения программного обеспечения становится трудно охватить и представить его как единое целое. Декомпозиция – разделе­ние задачи на мелкие подзадачи, установление между ними связей и ре­шение каждой из них независимо – приводит к построению программ­ного обеспечения из отдельных программных модулей, каждый из ко­торых представляет завершенную программу, решающую часть
общей
задачи.
44
Модульное программирование – это организация программы как со­вокупности небольших независимых блоков, называемых модулями.
Модуль – это самостоятельный, функционально законченный фраг­мент программы, имеющий определенное назначение и обеспечиваю­щий заданные функции обработки автономно от других программных модулей.
Разделение программного обеспечения на модули позволяет упро­стить реализацию, облегчить понимание кода программы и работы с данными, имеющими сложную структуру, а также избежать чрезмер­ной детализации алгоритмов больших программ, перенеся подробное рассмотрение реализации тех или иных действий на алгоритмы моду­лей. Кроме того, модульная структура позволяет распределить работы по исполнителям, обеспечив приемлемую их загрузку и требуемые сроки разработки программных продуктов.
Иерархия модулей. Разделение модулей на
иерархические уровни в структурном программировании производится по принципу вложен­ности. При этом используется вертикальное управление, для которого характерно то, что обращение к любому модулю может происходить только из какого-либо модуля более высокого уровня. Следовательно, на верхнем уровне должен быть единственный модуль (ведущая про­грамма), управление которым происходит из операционной системы Взаимодействие равноуровневых модулей при вертикальном управле­нии происходит только через модуль более высокого уровня.
К модулям предъявляются следующие требования:
отдельная компиляция;  один вход и один выход – на входе программный модуль получает
определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор выходных данных, т. е. реализу-
стандартный принцип IPO (Input – Process – Output) – вход – про-
ется цесс – выход;
выполнение минимального числа функций;  функциональная завершенностьмодуль выполняет перечень ре-
гламентированных операций, достаточных для реализации каждой от­дельной функции;
логическая независимость – результат работы программного мо-
дуля зависит только от исходных данных, но не зависит от источника входных данных, места назначения выходных
данных и работы других
.
45
модулей. Другими словам, всё, что может изменить работу программы (модуля), должно находиться вне программы (модуля);
слабые информационные связи с другими программными моду-
лями – обмен информацией между модулями должен быть по возмож­ности минимизирован;
соответствие принципу вертикального управления;  возможность вызова других модулей;  обозримый по размеру и сложности
программный элемент;
независимость от истории вызовов (реентерабельность). Степень независимости модулей оценивают двумя критериями:
сцеплением и связностью.
Сцепление является мерой взаимозависимости модулей, которая определяет, насколько хорошо модули отделены друг от друга. Модули независимы, если каждый из них не содержит никакой информации о других модулях. Чем больше информации о других модулях хранит
мо­дуль, тем больше он с ними сцеплен. Уменьшение зависимости модулей улучшает технологичность проекта, поскольку чем выше степень неза­висимости модулей, тем:
легче разобраться в отдельном модуле и всей программе и соот-
ветственно тестировать, отлаживать и модифицировать ее;
меньше вероятность появления новых ошибок при исправлении
старых или внесении
изменений в программу, т. е. вероятность появле-
ния «волнового» эффекта;
проще организовать разработку программного обеспечения груп-
пой программистов и легче его сопровождать.
Различают пять типов сцепления модулей:
по данным;  по образцу;  по управлению;  по общей области данных;  по содержимому.
Сцепление по данным предполагает, что модули
обмениваются дан-
ными, представленными скалярными значениями. При небольшом ко­личестве передаваемых параметров этот тип обеспечивает наилучшие технологические характеристики программного обеспечения.
Сцепление по образцу предполагает, что модули обмениваются данными, объединенными в структуры. Этот тип также обеспечивает неплохие характеристики, но они хуже, чем у предыдущего типа,
46
поскольку конкретные передаваемые данные «спрятаны» в структуры, и потому уменьшается «прозрачность» связи между модулями. Кроме того, при изменении структуры передаваемых данных необходимо мо­дифицировать все использующие ее модули.
При сцеплении по управлению один модуль посылает другому не­который информационный объект (флаг), предназначенный для управ­ления внутренней логикой модуля. Таким способом часто
выполняют настройку режимов работы программного обеспечения. Подобные настройки снижают наглядность взаимодействия модулей и потому обеспечивают еще худшие характеристики технологичности разраба­тываемого программного обеспечения по сравнению с предыдущими типами связей.
Сцепление по общей области данных предполагает, что модули ра-
ботают с общей областью данных.
программы, использующие этот тип сцепления, очень
сложны для
понимания при сопровождении программного обеспечения;
ошибка одного модуля, приводящая к изменению общих данных,
может проявиться при выполнении другого модуля, что существенно усложняет локализацию ошибок;
при ссылке к данным в общей области модули используют кон-
кретные имена, что уменьшает гибкость разрабатываемого программ­ного обеспечения.
Сцепления по содержимому – модуль
может содержать обращения к внутренним компонентам другого модуля, т. е. фактически его фраг­менты являются частью другого модуля, что противоречит блочно­иерархическому подходу.
В табл. 1 показаны особенности модулей с разными типами сцепления.
Таблица 1
Устойчивость
Тип
сцепления
По данным Хорошая Хорошая Хорошая Большая По образцу Средняя Хорошая Средняя Средняя По управлению Средняя Плохая Плохая Малая По общей области Плохая Плохая Средняя Малая По содержимому Плохая Плохая Плохая Малая
к ошибкам
других моду-
лей
Наглядность
(понятность)
47
Возможность
изменения
Вероятность
повторного использова-
ния
Связность – мера прочности соединения функциональных и инфор­мационных объектов внутри одного модуля. Если сцепление характери­зует качество отделения модулей, то связность характеризует степень взаимосвязи элементов, реализуемых одним модулем. Размещение сильно связанных элементов в одном модуле уменьшает межмодульные связи и соответственно взаимовлияние модулей. В то же время помеще­ние сильно связанных элементов
в разные модули не только усиливает межмодульные связи, но и усложняет понимание их взаимодействия. Объединение слабо связанных элементов также уменьшает технологич­ность модулей, поскольку такими элементами сложнее мысленно мани­пулировать.
Различают следующие виды связности (в порядке убывания уровня):
функциональную; последовательную; информационную (коммуникативную); процедурную; временную;
логическую;
  случайную.
При функциональной связности все объекты модуля предназначены для выполнения одной функции (операции, объединяемые для выпол­нения одной функции, или данные, связанные с одной функцией). Мо­дуль, элементы которого связаны функционально, имеет четко опреде­ленную цель, при его вызове выполняется одна задача, например, под­программа поиска минимального элемента массива
. Такой модуль имеет максимальную связность, следствием которой являются его хоро­шие технологические качества, проявляющиеся в простоте тестирова­ния, модификации и сопровождения.
Именно с этим связано одно из требований структурной декомпози­ции «один модуль – одна функция». Из тех же соображений следует из­бегать неструктурированного распределения функции между моду­лями – библиотеками ресурсов.
При последовательной связности функций выход одной функции служит исходными данными для другой функции. Как правило, такой модуль имеет одну точку входа, т. е. реализует одну подпрограмму, вы­полняющую две функции. Считают, что данные, используемые после­довательными функциями, также связаны последовательно. Модуль
48
с последовательной связностью функций можно разбить на два модуля или более как с последовательной, так и с функциональной связностью. Такой модуль выполняет несколько функций, и, следовательно, его тех­нологичность хуже: сложнее организовать тестирование, а при выпол­нении модификации мысленно приходится разделять функции модуля.
Информационно связанными считают функции, обрабатывающие одни и те
же данные. При использовании структурных языков програм­мирования раздельно выполнять функции можно, только если каждая функция реализуется своей подпрограммой.
Поскольку все функции, работающие с некоторыми данными, со­браны в одном месте, это позволяет при изменении формата данных корректировать только один модуль, что обеспечивает неплохие пока­затели технологичности. Информационно связанными считают
также
данные, которые обрабатываются одной функцией.
Процедурно связаны функции или данные, которые являются ча­стями одного процесса. Обычно модули с процедурной связностью функций получают, если в модуле объединены функции альтернатив­ных частей программы. При процедурной связности отдельные эле­менты модуля связаны крайне слабо, так как реализуемые ими действия связаны лишь общим
процессом, следовательно, технологичность та-
кого вида связи ниже, чем предыдущего.
Временная связность функций подразумевает, что эти функции выполняются параллельно или в течение некоторого периода. Времен­ная связность данных означает, что они используются в некотором временном интервале. Например, временную связность имеют функ­ции, выполняемые при инициализации некоторого процесса. Отличи­тельная особенность
временной связности в том, что действия, реали­зуемые такими функциями, обычно могут выполняться в любом по­рядке. Содержание модуля с временной связностью функций имеет тенденцию меняться: в него могут включаться новые действия и/или исключаться старые.
Большая вероятность модификации функций еще больше умень­шает показатели технологичности модулей этого вида по сравнению с предыдущим.
Логическая связь базируется на объединении данных или функций в одну логическую группу. В качестве примера можно привести функции обработки текстовой информации или данные одного и того же типа. Модуль с логической связностью функций часто реализует
49
альтернативные варианты одной операции, например сложение целых чисел и сложение вещественных чисел. Из такого модуля всегда будет вызываться одна какая-либо его часть, при этом вызывающий и вызы­ваемый модуль будут связаны по управлению. Понять логику работы модулей, содержащих логически связанные компоненты, как правило, сложнее, чем модулей, использующих временную связность, следова тельно, их показатели технологичности еще ниже.
В том случае, если связь между элементами мала или отсутствует, считают, что они имеют случайную связность. Модуль, элементы кото­рого связаны случайно, имеет самые низкие показатели технологично­сти, так как элементы, объединенные в нем, вообще не связаны.
В табл. 2 показаны особенности модулей с разными
видами связно-
сти.
Таблица 2
-
Вид связности
Функциональная Хорошая Хорошая Хорошая
Последовательная Хорошая Хорошая Хорошая
Информационная Средняя Средняя Средняя
Процедурная Средняя Средняя Плохая
Временная Средняя Средняя Плохая
Логическая Плохая Плохая Плохая
Случайная Плохая Плохая Плохая
Наглядность (понятность)
Возможность
изменения
Сопровождаемость
ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
Объектно-ориентированное программирование (ООП) – парадигма программирования, в которой основными концепциями являются поня­тия объектов и классов. При этом структура программы описывается в терминах объектов и связей между ними, а поведение системы описы­вается в терминах обмена сообщениями между объектами.
Структура и поведение сходных объектов определяют общий для них класс. Объекты одного
класса имеют одинаковое поведение и оди­наковые характеристики (атрибуты), но значения их атрибутов могут быть разными.
50
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]