Методику структурного подхода к алгоритмизации и программированию. Объектно-ориентированное программирование. Структурный подход в программировании. Что нам говорит Флойд о парадигмах

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

Характерными принципами структурного программирования являются:

· нисходящее программирование – способ разработки программ, при котором программи­рование ведется методом «сверху-вниз», от общего к деталям;

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

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

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

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

Следование– это линейная последовательность действий (рис. 2.6):

Рис. 2.6. Следование

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

Ветвление алгоритмическая альтернатива. Управление передается одному из двух блоков в зависимости от истинности или ложности условия. Затем происходит выход на общее продолжение (рис. 2.7):

Рис. 2.7. Ветвление

Цикл повторение некоторой группы действий по условию. Различаются два типа цикла. Первый цикл с предусловием (рис. 2.8):

Рис. 2.8. Цикл с предусловием

Пока условие истинно, выполняется серия, образующая тело цикла.

Второй тип циклической структуры цикл с постусловием (рис. 2.9):

Рис. 2.9. Цикл с постусловием

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

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

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

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

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

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

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

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

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

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

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

«сверху вниз»: сначала строится основной алгоритм, затем вспомогательные алгоритмы;

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

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

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

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

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

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

Лекция 1. Объектно-ориентированное программирование.

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

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

Другими факторами, влияющими на эволюцию методов проектиро­вания и создания ПП, являются:

Изменение архитектур вычислительных средств (ВС) в интересах повышения
производительности, надежности;

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

Выделяют 5-ть источников сложности программирования:

Решаемая задача;

Язык программирования;

Среда выполнения программы;

Технологический процесс коллективной разработки и создания ПП;

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

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

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

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


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

Теоретическое оформление структурный подход получил в нача­ле 70-х годов в работах теоретиков и практиков программирования(А.П.Ершова, Э. Йодана, Н.Вирта). Следует отметить появле­ние структурного программирования, в котором нашла определенное отражение идея упорядочивания структуры программы. Структурное программирование ориентирует на составление программ, структура которых близка к «дереву» опе­раторов или блоков. Использование структуры типа «дерево» в качестве своеоб­разного эталона объясняется тем, что это простая для анализа и реализации структура.

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

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

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

Развитие языков в направлении повышения эффективности составления приклад­ных программ привело к разделению языков по следующим уровням:

Низкий уровень (машинно-ориентированные языки - языки ассемблера),

Высокий уровень (процедурно-ориентированные языки: FORTRAN, ALGOL,

Уровень решаемой задачи (проблемно-ориентированные языки - SQL).

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

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

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

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

Язык программирования позволяет описать свойства моделируемых объектов и порядок манипуляции с объектами или порядок их взаимодействия, сообразуясь с условиями решаемой задачи. Первые языки программирования ориентировались на математические объекты, на определенную модель вычислителя. Поэтому они содержали такие конструкции как переменная, константа, функция, формальные и факти­ческие параметры. Программисты представляли свои программы в виде взаимодей­ствующих функций и модулей. Характер програм­мирования был процедурно-ориентированным, поскольку первостепенное внимание уделялось последовательностям действий с данными. Соответственно такие языки программирования, как FORTRAN, PL-1, С называют процедурно-ориентированными.

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

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

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

Объектный подход начал развиваться в программировании с 70-х годов (Smalltalk, CLOS, Ada). Эти языки называются объектными . Иерархическая классификация объектов инаследование свойств являются отправными идеями появившегося в 80-х годах объектно-ориентированного подхода. Одной из причин сравнительно медленного становления объектно-ориентированного стиля программирования яв­ляется его существенное отличие от процедурно-ориентирован­ного стиля.

Начало информационного этапа

Развитие человечества все больше и больше наталкивало величайшие умы на мысли об автоматизации некоторых процессов. Начало этапа программирования приписывается по разным источникам нескольким периодам в промежутке от начала 19 до середины 20 веков. За эти десятилетия появилось множество методик написания исходного кода. Каждая из них кардинально отличается своими принципами и идеями. Рассмотрим структурное программирование, появившееся в 70-х годах прошлого столетия.

Немного истории

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

Основные принципы структурного программирования

Рассмотрим подробно основные моменты структурного подхода.

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

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

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

Языки программирования

С разработкой данной методологии стали появляться и развиваться языки программирования. Структурный подход реализуют такие известные из них, как Pascal (Паскаль), C (Си), а также более устаревший - Algol (Алгол).

Эпилог

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

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

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

Простой последовательности;

Условий или альтернатив;

Повторений, то есть циклов и итераций.

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

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

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

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

Если говорить о позиции относительно ранее упомянутого оператора go to, то его стоит избегать использовать везде, где только возможно, однако это никак не должно отражаться на ясности программы. Иногда использование данного оператора оказывается просто необходимым для выхода из какого-то отрезка программы или цикла, а также для того, чтобы избежать появления слишком углубленных развилок, тем более, что переход связан с более нижними уровнями программ. При этом структура программы так и остается легко читаемой сверху вниз. Самый худший данного оператора связан с переходом снизу вверх.

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

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

технологических приемов, охватывающих выполнение всех этапов разработки программного

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

систем с целью последующей реализации в виде отдельных небольших (до 40 - 50 операторов)

подпрограмм. С появлением других принципов декомпозиции (объектного, логического и т. д.)

данный способ получил название процедурной декомпозиции.

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

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

Проектирование, таким образом, осуществлялось «сверху вниз» и подразумевало реализацию

общей идеи, обеспечивая проработку интерфейсов подпрограмм. Одновременно вводились ог-

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

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

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

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

локализацию и ограничение области «видимости» данных. Среди наиболее известных языков этой

группы стоит назвать PL/1, ALGOL-68, Pascal, С.

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

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

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

версиях развиваемых языков.

Дальнейший рост сложности и размеров разрабатываемого программного обеспечения

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

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

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

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

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

Модульное программирование предполагает выделение групп подпрограмм, использующих

одни и те же глобальные данные в отдельно компилируемые модули (библиотеки подпрограмм),

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

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

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



«внутренним» переменным) запрещен. Эту технологию поддерживают современные версии

языков Pascal и С (C++), языки Ада и Modula.

Использование модульного программирования существенно упростило разработку

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

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

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

позволяет получать достаточно надежные программы, размер которых не превышает 100 000

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

интерфейсе при вызове подпрограммы выявляется только при выполнении программы (из-за

раздельной компиляции модулей обнаружить эти ошибки раньше невозможно). При увеличении

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

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

невозможно. Для разработки программного обеспечения большого объема было предложено

использовать объектный подход .