Методы и технологии программирования
Структурное программирование
Разработка алгоритмов «сверху -
вниз»
Для специалистов, решающих с помощью ЭВМ те или иные задачи, разработка
алгоритма решения является важнейшим делом. Существуют различные методы
разработки алгоритмов (и программ), но наиболее важным является метод пошаговой
детализации (или метод разработки « сверху - вниз »). При этом методе
первоначально продумывается и фиксируется множество данных и результатов
алгоритма без детальной проработки отдельных частей.
Задачу разбивают на автономные части, каждая из которых существенно проще.
Может оказаться необходимым повторять процесс детализации многократно, но это
определяется только сложностью решаемых задач. Конечным уровнем детализации
алгоритма можно считать такой, при котором в алгоритме нет действий более
крупных, чем: обращение к готовому алгоритму; вычисление арифметического
выражения и присваивание значения переменной; сравнение арифметических
выражений (или переменных); ввод (вывод) данных и т.п.
Главным требованием к алгоритму, несомненно, является его
работоспособность. Однако создавая алгоритм, необходимо помнить о дальнейшей
работе над ним, об отладке программы, которая будет создана по этому алгоритму,
а также о вероятных пользователях, которым, возможно, потребуется этот
алгоритм. Поэтому одним из важнейших требований к алгоритму является его
простота и понятность.
Исходя из этих требований, особенно удобным представляется при разработке
алгоритмов использование основных алгоритмических структур. Их важной
особенностью является то, что они имеют один вход и один выход и могут
соединяться друг с другом в любой последовательности. Это дает наглядную и
простую структуру алгоритма, по которой легче составить программу.
Одним из основных требований к программам
является ее адаптируемость. Программа является
адаптируемой, если она допускает быструю модификацию с целью приспособления к
изменяющимся условиям функционирования. Адаптируемость
означает, что внесение небольших изменений не потребует кардинальной
переработки всего программного продукта. Адаптируемость
определяется многими факторами, причем одним из важнейших является понимаемость исходного текста.
Обычно при составлении схемы алгоритма процесс вычисления идет сверху вниз,
возвращаясь назад только в циклах, что позволяет анализировать алгоритм как
обычный текст, т.е. сверху вниз.
Если технологию разработки алгоритмов «сверху - вниз »
совместить с использованием только структурных схем, то получится новая
технология, которая называется структурным программированием сверху - вниз, идея которого заключается в том,
что структура программы должна отражать структуру решаемой задачи, чтобы
алгоритм решения был ясно виден из исходного текста. Для этого надо иметь средства
для создания программы не только с помощью трех простых операторов, но и с
помощью средств, более точно отражающих конкретную структуру алгоритма. С этой
целью в программирование введено понятие подпрограммы
— набора операторов, выполняющих нужное действие и не зависящих от
других частей исходного кода. Программа разбивается на множество мелких
подпрограмм (занимающих до 50 операторов — критический порог для быстрого
понимания цели подпрограммы), каждая из которых выполняет одно из действий,
предусмотренных исходным заданием. Комбинируя эти подпрограммы, удается
формировать итоговый алгоритм уже не из простых операторов, а из законченных
блоков кода, имеющих определенную смысловую нагрузку, причем обращаться к таким
блокам можно по названиям. Получается, что подпрограммы — это новые операторы
или операции языка, определяемые программистом.
Возможность применения подпрограмм относит язык
программирования к классу процедурных языков.
Нисходящее проектирование
Наличие подпрограмм позволяет вести проектирование и
разработку приложения сверху вниз —
такой подход называется нисходящим
проектированием. Сначала выделяется несколько подпрограмм, решающих
самые глобальные задачи (например, инициализация данных, главная часть и
завершение), потом каждый из этих модулей детализируется на более низком
уровне, разбиваясь в свою очередь на небольшое число других подпрограмм, и так
происходит до тех пор, пока вся задача не окажется реализованной.
Такой подход удобен тем, что позволяет человеку постоянно мыслить на
предметном уровне, не опускаясь до конкретных операторов и переменных. Кроме
того, появляется возможность некоторые подпрограммы не реализовывать сразу, а
временно откладывать, пока не будут закончены другие части. Например, если
имеется необходимость вычисления сложной математической функции, то выделяется
отдельная подпрограмма такого вычисления, но реализуется она временно одним
оператором, который просто присваивает заранее выбранное значение (например,
5). Когда все приложение будет написано и отлажено, тогда можно приступить к
реализации этой функции.
Немаловажно, что небольшие подпрограммы значительно проще
отлаживать, что существенно повышает общую надежность всей программы.
Очень важная характеристика подпрограмм — это возможность их повторного использования. С
интегрированными системами программирования поставляются большие библиотеки
стандартных подпрограмм, которые позволяют значительно повысить
производительность труда за счет использования чужой работы по созданию часто
применяемых подпрограмм.
Подпрограммы бывают двух видов — процедуры и функции. Отличаются
они тем, что процедура просто выполняет группу операторов, а функция вдобавок
вычисляет некоторое значение и передает его обратно в главную программу (возвращает значение). Это значение
имеет определенный тип (говорят, что функция имеет такой-то тип).
Чтобы работа подпрограммы имела смысл, ей надо получить
данные из внешней программы, которая эту подпрограмму вызывает. Данные передаются подпрограмме в виде параметров или аргументов, которые обычно
описываются в ее заголовке так же, как переменные.
Подпрограммы вызываются, как правило, путем простой
записи их названия с нужными параметрами. В Бейсике есть оператор CALL для явного указания того, что происходит вызов подпрограммы.
Подпрограммы активизируются только в момент их вызова. Операторы, находящиеся внутри
подпрограммы, выполняются, только если эта подпрограмма явно вызвана. Пока
выполнение подпрограммы полностью не закончится, оператор главной программы,
следующий за командой вызова подпрограммы, выполняться не будет.
Подпрограммы могут быть вложенными — допускается вызов подпрограммы не
только из главной программы, но и из любых других подпрограмм.
В некоторых языках программирования допускается вызов
подпрограммы из себя самой. Такой прием называется рекурсией и потенциально опасен тем, что может привести к
зацикливанию — бесконечному самовызову.
Подпрограмма состоит из нескольких частей: заголовка с
параметрами, тела подпрограммы (операторов, которые будут выполняться при ее
вызове) и завершения подпрограммы.
Локальные переменные, объявленные внутри подпрограммы, имеют областью действия
только ее тело.
После того как функция рассчитала нужное значение, ей
требуется явно вернуть его в вызывающую программу. Для этого может
использоваться специальный оператор (return в Си++) или особая форма оператора присваивания,
когда в левой части указывается имя функции, а справа — возвращаемое значение.
Пример функции, вычисляющей значение квадрата аргумента в
Бейсике:
FUNCTION
SQR% (X AS INTEGER)
SQR% = X*X
END FUNCTION
Во время создания подпрограммы заранее не известно, какие
конкретно параметры она может и будет получать.
Поэтому в качестве переменных, выступающих в роли ее аргументов в заголовке,
могут использоваться произвольные допустимые названия, даже совпадающие с уже имеющимися. Компилятор все равно поймет, что это не одно и
то же.
Параметры, которые указываются в заголовке подпрограммы,
называются формальными. Они
нужны только для описания тела подпрограммы. А параметры (конкретные значения),
которые указываются в момент вызова подпрограммы, называются фактическими параметрами. При выполнении
операторов подпрограммы формальные параметры как бы временно заменятся на фактические.
Пример.
int а,у;
а = 5;
у = SQR(a);
Программа вызывает функцию SQR() с одним фактическим параметром «а». Внутри подпрограммы формальный
параметр «х» получает значение переменной «а» и возводится
в квадрат. Результат возвращается обратно в программу и присваивается
переменной «у».
Событийно-ориентированное
программирование
С активным распространением системы Windows и появлением визуальных RAD-сред широкую популярность
приобрел событийный подход к созданию программ — событийно-ориентированное программирование.
Идеология системы Windows основана на событиях. Щелкнул человек на кнопке, выбрал пункт меню, нажал
на клавишу или кнопку мыши — в Windows генерируется подходящее сообщение,
которое отсылается окну соответствующей программы.
Структура программы, созданной с помощью событийного
программирования, следующая. Главная часть представляет собой один бесконечный
цикл, который опрашивает Windows, следя за тем, не появилось
ли новое сообщение. При его обнаружении вызывается подпрограмма, ответственная
за обработку соответствующего
события (обрабатываются не все события, их сотни, а только нужные), и подобный
цикл опроса продолжается, пока не будет получено сообщение «Завершить работу»,
События могут быть пользовательскими,
возникшими в результате действий пользователя, системными, возникающими в операционной системе (например,
сообщения от таймера), и программными,
генерируемыми самой программой (например, обнаружена ошибка и ее надо обработать).
Событийное программирование является развитием идей
нисходящего проектирования, когда постепенно определяются и детализируются
реакции программы на различные события.
Объектно-ориентированное программирование.
Понятие объекта
Развитие идей структурного и событийного программирования
существенно подняло производительность труда программистов и позволило в
разумные сроки (несколько месяцев) создавать приложения объемом в сотни тысяч
строк. Однако такой объем уже приблизился к пределу возможностей человека, и
потребовались новые технологии разработки программ.
В начале 80-х годов в программировании возникло новое
направление, основанное на понятии объекта.
До того времени основные ограничения на возможность создания больших
систем накладывала разобщенность в программе данных и методов их обработки.
Реальные объекты окружающего мира обладают тремя базовыми характеристиками:
они имеют набор свойств, способны разными методами изменять эти свойства и
реагировать на события, возникающие как в окружающем мире, так и внутри самого
объекта. Именно в таком виде в языках программирования и реализовано понятие объекта как совокупности свойств (структур данных, характерных
для этого объекта), методов их
обработки (подпрограмм изменения свойств) и событий, на которые данный объект может
реагировать и которые приводят, как правило, к изменению свойств
объекта.
Появление возможности создания объектов в программах
качественно повлияло на производительность труда программистов. Максимальный
объем приложений, которые стали доступны для создания группой программистов из
10 человек, за несколько лет увеличился до миллионов строк кода, при этом
одновременно удалось добиться высокой надежности программ и, что немаловажно,
повторно использовать ранее созданные объекты в других задачах.
Объекты могут иметь идентичную структуру и отличаться
только значениями свойств. В таких случаях в программе создается новый тип,
основанный на единой структуре объекта (по аналогии с тем, как создаются новые
типы для структур данных). Он называется классом,
а каждый конкретный объект, имеющий структуру этого класса, называется экземпляром класса.
Описание нового класса похоже на описание новой структуры
данных, только к полям (свойствам) добавляются методы — подпрограммы.
При определении подпрограмм, принадлежащих конкретному
классу, его методов, в заголовке подпрограммы перед ее названием явно
указывается, к какому классу она принадлежит.
Класс — это тип данных, такой же, как любой другой
базовый или сложный тип. На его основе можно описывать конкретные объекты
(экземпляры классов).
Объектно-ориентированное программирование базируется на
трех ключевых концепциях — инкапсуляции, наследовании и полиморфизме.
Объединение данных с методами в одном типе (классе)
называется инкапсуляцией. Помимо
объединения, инкапсуляция позволяет ограничивать доступ к данным объектов и
реализации методов классов. В результате у программистов появляется возможность
использования готовых классов в своих приложениях на основе только описаний
этих классов.
Важнейшая характеристика класса — возможность создания на
его основе новых классов с наследованием
всех его свойств и методов и добавлением собственных. Класс, не имеющий
предшественника, называется базовым.
Например, класс «животное» имеет свойства «название»,
«размер», методы «идти» и «размножаться». Созданный
на его основе класс «кошка» наследует все эти свойства и методы, к которым
дополнительно добавляется свойство «окраска» и метод «пить».
Наследование позволяет создавать новые классы, повторно
используя уже готовый исходный код и не тратя времени на его переписывание.
В большинстве случаев методы базового класса у классов -
наследников приходится переопределять — объект класса «кошка» выполняет метод
«идти» совсем не так, как объект класса «амеба». Все переопределяемые методы по
написанию (названию) будут совпадать с методами базового объекта, однако
компилятор по типу объекта (его классу) распознает, какой конкретно метод надо
использовать, и не вызовет для объекта класса «кошка» метод «идти» класса
«животное». Такое свойство объектов переопределять методы наследуемого класса и
корректно их использовать называется полиморфизмом.
Технологии объектного, событийного и структурного программирования сегодня
объединены в RAD-системах, которые содержат множество готовых классов, представленных в
виде визуальных компонентов, которые
добавляются в программу одним щелчком мыши. Программисту надо только
спроектировать внешний вид окон своего приложения и определить обработку
основных событий — какие операторы будут выполняться
при нажатии на кнопки, при выборе пунктов меню или щелчках мышкой. Весь
вспомогательный исходный код среда сгенерирует сама, позволяя программисту
полностью сосредоточиться только на реализации алгоритма.