7.3. РЕТРОСПЕКТИВНОЕ ПРОЕКТИРОВАНИЕ ДЕМОНСТРАЦИОННОЙ ПРОГРАММЫ MCALC ФИРМЫ «BORLAND INC.»
Согласно ретроспективно проведенного системного анализа (см. гл. 2), фирма «Borland Inc.» приняла решение о реализации демонстрационного примера программы электронной таблицы. Вполне возможно сгенерировать множество вариантов реализации электронной таблицы, начиная от варианта со всеми клетками в одном окне и кончая, например, вариантом Excel. Однако фирма «Borland Inc.» избрала вариант с прокруткой информации клеток в окне, изменением адресов клеток при вставках строк и столбцов, а также при их удалении. В проект введены требования разработки некоммерческого изделия. Размер таблицы ограничен 100–100 клетками. В программе отсутствует функция копирования клеток. Избранная сложность реализуемого варианта соответствует многофайловому проекту. Программа имеет функции поддержки вывода на дисплей, ввода с клавиатуры; в ней реализован интерпретатор формул с математическими функциями; для сохранения информации таблицы используется файл сложной организации, рассмотренный в гл. 3. Все это позволяет продемонстрировать возможности компилятора.
Программа Mcalc 1985–1988 гг. (Turbo Pascal 5.0) состоит из следующих файлов:
• mcalc.pas — файл основной программы;
• mcvars.pas — файл глобальных описаний;
• mcdisply.pas — файл подпрограмм работы с дисплеем;
• mcmvsmem.asm — ассемблерный файл подпрограмм запоминания в оперативной памяти информации экрана, а также восстановления ранее сохраненной информации экрана;
• mcinput.pas — файл подпрограмм ввода данных с клавиатуры;
• mcommand.pas — файл подпрограмм, обслуживающих систему меню и действий, выбранных посредством меню;
• mcutil.pas — файл вспомогательных подпрограмм;
• mcparser.pas — файл интерпретатора арифметических выражений формул клеток.
Все файлы закодированы с соблюдением развиваемых стандартов оформления. Так, в файлах mcdisply.pas, mcinput.pas описания прототипов подпрограмм выполнены с использованием более раннего синтаксиса языка программирования, что говорит об их заимствовании из программ, написанных ранее; при этом можно выявить их небольшое модифицирование (рефакторинг).
Хотя фирма «Borland Inc.» занимается разработкой компиляторов, файл mcparser.pas также является заимствованным из UNIX YACC utility и лишь частично модифицированным. Остальные файлы являются оригинальными.
Ассемблерный файл mcmvsmem.asm является искусственно добавленным. Цель его добавления — демонстрация возможности использования ассемблерных вставок. Содержащиеся в нем алгоритмы вполне можно было бы реализовать на языке Pascal. Более того, можно было бы вообще обойтись без реализованных в нем подпрограмм, правда, при этом были бы видны некоторые задержки вывода информации на экран.
С целью совершения улучшающей проект новой проектной итерации получим из существующего проекта проектную документацию, состоящую из описания структуры данных программы; функционального описания основного ядра программы; схемы иерархии модулей основного ядра программы; спецификации назначения модулей основного ядра программы.
Рассмотрим организацию файла mcvars.pas, содержащего в основном описание структуры внутренних данных программы. Файл содержит описания в секции interface. Секция implementation пустая.
В начале файла содержится код, который в зависимости от наличия сопроцессора транслируется в одном из двух вариантов:
{$IFOPT N+}
{Есть встроенный сопроцессор}
type
Real = Extended; {Замена типа Real на Extended}
const
EXPLIMIT = 11356; {Предельное значение аргумента экспоненты}
SQRLIMIT = 1Е2466;{Предельное значение аргумента SQRT}
….
{$ELSE}
const
{Тип Real не переопределен}
EXPLIMIT = 88; {Предельное значение аргумента экспоненты}
SQRLIMIT = 1E18; {Предельное значение аргумента SQRT}
….
{$ENDIF}
Описания констант содержат следующие блоки:
— блок строчных констант, содержащих информацию всех выводимых на экран и в файлы текстовых надписей (для русификации всей программы требуется изменить только эту информацию);
— блок парных строк текстов меню и «горячих» клавиш выбора тем меню;
— блок описания важнейших констант, определяющих размерность таблицы и расположение информации на экране
MAXCOLS = 100; { Maximum is 702 } {Размер таблицы}
MAXROWS = 100;
MINCOLWIDTH = 3; {Минимальная ширина столбца}
MAXCOLWIDTH = 77; {Максимальная ширина столбца}
….
— блок описания цветов всех полей экрана, модификация констант которого позволяет оперативно изменять цвета;
— основные константы, мнемоника имен которых облегчает восприятие текстов программы
HIGHLIGHT = True; {Подсвеченная текущая клетка}
NOHIGHLIGHT = False; {Неподсвеченная клетка}
{Атрибут содержимого клетки}
ТХТ = 0;
VALUE = 1;
FORMULA = 2;
….
{Разрешенные буквы}
LETTERS: set of Char = [‘A’..’Z’, ‘a’..’z’];
— коды управляющих клавиш клавиатуры.
Следует отметить, что приведены даже коды неиспользуемых в программе управляющих клавиш клавиатуры. Это соответствует факту копирования данных кодов из кода какой-то другой разработки.
Далее следуют описания типа информации содержимого табличной клетки и типа указателя на клетку:
type
CellRec = record
Error: Boolean;
case Attrib: Byte of
TXT: (T: IString);
VALUE: (Value: Real);
FORMULA: (Fvalue: Real;
Formula: IString);
end;
CellPtr = ^CellRec; {Указатель на клетку}
Данный тип организован так, что клетка всегда может содержать признак ошибки расчетов Error и размещать три варианта информации: текст, значение и формулу.
Далее описаны основные глобальные переменные. Описания начинаются с определения двухмерного, постоянно находящегося в памяти массива Cell указателя на клетки таблицы. Это позволяет не расходовать память на пустые клетки. Память под информацию клетки выделяется динамически в количестве, строго соответствующем информации клетки. Без использования динамически выделяемой памяти было бы невозможно разместить информацию клеток таблицы в 640К памяти машин того времени.
MAXCOLS*MAXROWS*[SizeOf(Istring)+SizeOf(Extened)] = 100*100*[80+10] = 900K
Далее следуют описание переменной, являющейся указателем на текущую клетку таблицы, описание массива форматов клеток и переменных позиционирования информации на экране.
Cell: array [1..MAXCOLS, 1..MAXROWS] of CellPtr;
CurCell: CellPtr; {Указатель на текущую клетку}
Format: array [1..MAXCOLS, 1..MAXROWS] of Byte;
LeftCol, RightCol, TopRow, BottomRow,
{Позиционирование}
CurCol, CurRow, LastCol, LastRow: Word;
….
Следует отметить, что выделение отдельного массива форматов информации клеток является не оправданным. Практичнее ввести байт информации формата клетки в тип CellRec.
Сравните этот проект структуры данных с проектом структуры данных электронной таблицы, представленной в гл. 3.
Для составления оставшейся проектной документации выполним трассировку программы. После двойного нажатия клавиши начинает исполняться настроечный код, содержащийся в файлах *.TPU, и далее начинают выполняться операторы основной программы program Mcalc, находящейся в файле mcalc.pas.
В результате исследований была выявлена схема иерархии модулей программы, изображенная на рис. 7.3–7.5. Расшифровка обозначений схемы иерархии представлена в табл. 7.1.
Рис. 7.3. Фрагмент схемы иерархии основных модулей программы
Рис. 7.4. Схема иерархии модуля RedrawScreen
Рис. 7.5. Сокращенная схема иерархии модуля Run
Таблица 7.1
Расшифровка обозначений схемы иерархии
| Имя модуля | Файл | Назначение модуля |
| Act | Mclib | Обрабатывает информацию введенной строки, занося ее в клетку |
| CenterColString | Mcutil | Рассчитывает X координату центрируемой в поле вывода строки |
| ChangeAutoCalc | Mclib | Устанавливает автоматический и ручной режимы рекалькуляции таблицы |
| ChangeFormDisplay | Mclib | Устанавливает режим видимости значений формул или текста формул |
| ClearInput | Mcdisplay | Очищает на экране поле строки ввода |
| ClrScr | Crt | Очищает информацию в окне экрана |
| DisplayCell | Mclib | Выводит на экран информацию клетки |
| DisplayScreen | Mclib | Отображает на экране внутреннюю информацию таблицы |
| EditCell | Mcommand | Осуществляет редактирование содержимого клетки |
| EditString | Mcinput | Редактор текстовой строки |
| EgaInstalled | Mcdisplay | Функция, определяющая наличие видеокарты EGA |
| FillChar | Dos | Присваивает элементам массива значение символа |
| GetCursor | Mcdisplay | Считывает толщину курсора в переменную |
| GetInput | Mcinput | Получив первый введенный символ, продолжает ввод информации клетки |
| GetKey | Mcinput | Формирует слово расширенного кода клавиши |
| GetSetCursor | Mcdisplay | Считывает толщину курсора в переменную и устанавливает новую толщину курсора |
| GotoXY | Mcdisplay | Перемещает курсор в соответствии с заданными координатами дисплея |
| InitColorTable | Mcdisplay | Инициализирует массив пересчета цветов для монохромного монитора |
| InitDisplay | Mcdisplay | Инициализирует видеокарту на работу в режиме 80-25 |
| InitVars | Mcutil | Инициализирует значения основных переменных программы |
| Intr | Dos | Вызывает прерывание MS DOS |
| LoadSheet | Mcommand | Загружает информацию таблицы из файла |
| MainMenu | Mcommand | Реализует выбор тем меню программы |
| Mcalc | Mcalc | Главная программа |
| ParamCount | Dos | Счетчик полей командной строки запуска программы Mcalc |
| ParamStr | Dos | Возвращает значения заданного поля командной строки запуска программы Mcalc |
| PrintCol | Mcdisplay | Выводит значение координаты колонки таблицы |
| PrintFreeMem | Mcdisplay | Выводит на экран значение остатка свободной памяти |
| PrintRow | Mcdisplay | Выводит значение координаты строки таблицы |
| ReadKey | Mcinput | Считывает короткий код одной нажатой клавиши |
| Recalc | Mclib | Осуществляет перерасчет значений формул клеток таблицы |
| RedrawScreen | Mclib | Отображает на экране всю информацию таблицы |
| Run | Mcalc | Главный цикл программы |
| Scroll | Mcdisplay | Прокручивает информацию экрана в указанном направлении; устанавливает цвет фона освободившейся части экрана |
| SetBottomRow | Mcdisplay | Выводит на экран столбец с номерами строк таблицы |
| SetColor | Mcdisplay | Устанавливает цвет вывода строк на экран |
| SetCursor | Mcdisplay | Устанавливает заданную толщину курсора |
| SetRightCol | Mcdisplay | Выводит на экран строку с наименованиями столбцов таблицы |
| ShowCellType | Mcdisplay | Выводит на экран надпись о типе текущей клетки таблицы |
| TextMode | Dos | Переводит экран в указанный текстовый режим |
| Window | Crt | Определяет окно на экране дисплея |
| Write | — | Оператор вывода языка Pascal |
| WriteXY | Mcdisplay | Осуществляет вывод заданного числа символов заданной строки по заданным координатам дисплея |
Рассмотрим функциональное описание основного ядра программы. В файле mcutil.pas исполняется рудиментарный, оставшийся от прежних разработок код:
HeapError:= @HeapFunc;
В файле mcdisplay.pas последовательно выполняются подпрограммы: InitDisplay, GetSetCursor, Window, EGAInsalled.
Процедура InitDisplay инициализирует видеокарту на работу в режиме 80 25 при помощи вызова прерывания 10h и вызовом процедуры InitColorTable инициализирует массив пересчета цветов для монохромного монитора. Последний массив используется при вызовах процедуры SetColor.
Процедура GetSetCursor при помощи процедуры GetCursor считывает толщину курсора в переменную OldCursor и при помощи процедуры SetCursor устанавливает новую толщину курсора (NOCURSOR).
Процедура Window определяет окно на экране дисплея для размещения информации всей таблицы. Далее начинает выполняться код главной программы Mcalc.
Присваиванием CheckBreak:= False запрещается использование клавиши немедленного завершения программы.
Вывод начальной заставки осуществляется следующими вызовами подпрограмм. Процедурами SetColor и ClrScr производится очистка окна программы. Двойным вызовом процедур SetColor и WriteXY выводятся две строки начальной заставки. Несмотря на отсутствие курсора, отрабатывается рудиментарный вызов «сокрытия» курсора GotoXY(80,25). При помощи функции GetKey осуществляется ожидание нажатия пользователем любой клавиши.
Процедурами SetColor и ClrScr производится очистка окна программы.
Вызовом процедуры InitVars инициализируются значения основных переменных программы. Массивы инициализируются значениями по умолчанию вызова процедуры FillChar.
Присваиванием Changed:= False указывается факт неизменности информации клеток таблицы после момента инициализации переменных для запрещения срабатывания автосохранения.
Вызовом процедуры RedrawScreen производится отображение на экране всей информации таблицы.
Если значение ParamCount = 1, то в командной строке MS DOS вызова программы было указано имя файла таблицы. В этом случае выполняется процедура LoadSheet, которая загружает информацию таблицы из файла с именем файла, полученном при помощи вызова функции ParamStr.
Наконец, отрабатывает «лишний» вызов Clearlnput, который дублируется в начале последующей процедуры Run, содержащей главный цикл программы.
При завершении выполнения программы последовательно производится установка цвета экрана, вызовом TextMode переводится экран в текстовый режим, запомненный в переменной OldMode, и, наконец, вызовом SetCursor восстанавливается толщина курсора, запомненная в переменной OldCursor.
Работа процедуры RedrawScreen заключается в последовательном выводе на экран информации:
• процедурой SetRightCol выводится на экран строка с наименованиями столбцов таблицы;
• процедурой SetBottomRow выводится на экран колонка с номерами строк таблицы;
• процедурами GotoXY и Write выводятся надписи в верхней строке экрана, хотя имеется более удобная процедура WriteXY;
• выводится число остатка байт памяти;
• процедурой DisplayScreen отображается на экране внутренняя информация таблицы.
Внешний вид программы Mcalc приведен на рис. 7.6.
Работа процедуры Run начинается с установления переменной главного цикла Stop:= False и выполнения процедуры Clearlnput. Главный цикл программы выполняется до изменения значения переменной Stop на True. Такое изменение возможно лишь при выборе пользователем темы меню Quit — завершение работы с программой.
Внутри главного цикла последовательно выполняются следующие действия:
— при помощи процедуры DisplayCell выводится на экран подсвеченная клеточным курсором текущая клетка (клетка А1 на рис. 7.6);
— при помощи процедуры ShowCellType выводится в нижнем левом углу экрана надпись типа текущей клетки таблицы (см. рис. 7.6);
— оператором Input:= GetKey в переменную Input вводится код символа клавиши, нажатой пользователем;
— выполняются действия отработки клавиши, нажатой пользователем.
Действия отработки клавиши, нажатой пользователем, представляют собой цепочку альтернативных действий, реализованную структурой ВЫБОР. Сначала отрабатываются действия «горячих» клавиш. В секции default (если клавиша не была «горячей») вызовом процедуры Getlnput начинается занесение информации в текущую клетку таблицы. Процедура Getlnput, занеся символ Input в редактируемую строку, первоначально вызывает EditString — редактор текстовой строки информации клетки и затем вызывает процедуру Act, которая обрабатывает информацию введенной строки, занося ее в клетку.
Рис. 7.6. Внешний вид программы Mcalc
Анализ схемы иерархии программы и функционального описания основного ядра программы показал, что основная программа перегружена вспомогательными действиями, выделение процедуры Run является искусственным разделением основной программы без продуманного структурного разбиения. Все это приводит к потере понятности текста программы.
С целью повышения понятности программы были приняты новые проектные решения, отраженные схемой иерархии (рис. 7.7).
Выполнение основной программы Mcalc начинается с запуска нового модуля Starting подготовительных действий программы. Модуль Starting является монитором последовательного исполнения модулей InitDisplay, Greeter, InitVars.
Новый модуль InitDisplay теперь является монитором последовательного исполнения модулей GetSetMode, GetCursor, SetCursor, Egalnstalled, Window, InitColorTable.
У нового модуля GetSetMode явно в качестве входного параметра указывается новый устанавливаемый видеорежим, а на выходе — старый видеорежим. Такая организация предпочтительнее прямого вызова Intr, поскольку по списку формальных параметров ясно видно назначение модуля. Реализация двух функций по выявлению и установке видеорежимов в одном модуле здесь вполне оправдана, поскольку все они реализуются вызовом одного прерывания.
Не является оправданным использование модуля с двумя функциями GetSetCursor, который являлся монитором последовательного исполнения модулей GetCursor, SetCursor. Этот модуль исключен из проекта. Все функции вывода начальной заставки переданы новому модулю Greeter.
Из модуля RedrawScreen исключен вызов модуля DisplayScreen. Это позволило избежать повторного вызова модуля DisplayScreen в модуле LoadSheet. Также исправлена ошибка использования операторов Write для вывода информации на экран путем использования вызовов процедуры WriteXY.
Далее начинает исполняться главный цикл программы. Модуль Run удален из проекта с целью увеличения понятности программы. Длинный текст выбора действий по коду нажатой пользователем клавиши заменен одной альтернативой:
If (not(HotKey(Input)) and (ConditionalKey(Input)))
then
GetInput(Input).
Новая функция HotKey в случае нажатия пользователем горячей клавиши возвращает значение TRUE, в противном случае функция возвращает значение FALSE.
Новая функция ConditionalKey в случае нажатия пользователем клавиши с кондиционным для занесения в таблицу кодом возвращает значение TRUE, в противном случае функция возвращает значение FALSE.
Рис. 7.7. Переработанная схема иерархии модулей программы
Новая процедура WriteXY теперь не использует вызов медленной процедуры GotoXY и медленно выполняемый оператор Write и использует прямой доступ к видеопамяти. Это позволило значительно ускорить вывод информации на дисплей. Более того, в процедуру добавлен новый параметр атрибута цвета выводимой строки, что позволило избежать цепочек первоначального вызова SetColor, а затем WriteXY.
Завершается выполнение программы вызовом нового модуля Finishing. Данный пример показал самодостаточность избранной проектной документации для получения нового оптимального варианта построения структуры программы.
ВЫВОДЫ
• Структура программы — искусственно выделенные программистом взаимодействующие части программы. Использование рациональной структуры устраняет проблему сложности разработки; делает программу понятной людям; повышает надежность работы программы при сокращении срока ее тестирования и сроков разработки вообще.
• Модуль — функциональный элемент технологии структурного программирования. Это подпрограмма, но оформленная в соответствии с особыми правилами.
• В понятие структуры программы включается состав и описание связей всех модулей, которые реализуют самостоятельные функции программы и описание носителей данных, участвующих в обмене как между отдельными подпрограммами, так и вводимыми и выводимыми с/на внешних устройств.
• Вероятно, наиболее общая тактика программирования состоит в разложении процесса на отдельные действия: функционального описания на подфункции, а соответствующих программ — на отдельные инструкции.
• Самым главным в схеме иерархии является минимизация усилий по сборке и тестированию программы. При использовании заглушек можно хорошо тестировать сопряжения модулей, но не сами модули. Тестирование самих модулей потребует изощренных сложных заглушек и астрономического числа тестов. Выход — до интеграции модулей тестировать модули с использованием ведущих программ.
• Схема иерархии должна отражаться на файлах с исходными текстами программ таким образом, чтобы каждый файл содержал как можно больше готовых функций с общим назначением. Это облегчит их использование в последующих разработках.
Контрольные вопросы
1. Дайте определение понятию «структура программы».
2. Что такое модуль программы и какими характеристиками он должен обладать?
3. Что отражает схема иерархии?
4. Какие принципы необходимо соблюдать, если следовать технологии структурного программирования?
5. Дайте определение понятию «заглушка модуля».
6. Перечислите основные средства изменения топологии схемы иерархии программы.
7. Назовите критерии оценки качества схемы иерархии.
8. Для чего нужен паспорт модуля?
7.1. ПОНЯТИЕ СТРУКТУРЫ ПРОГРАММЫ
Структура программы — искусственно выделенные программистом взаимодействующие части программы. Использование рациональной структуры устраняет проблему сложности разработки; делает программу понятной людям; повышает надежность работы программы при сокращении срока ее тестирования и сроков разработки вообще.
Часто некоторую последовательность инструкций требуется повторить в нескольких местах программы. Чтобы программисту не приходилось тратить время и усилия на копирование этих инструкций, в большинстве языков программирования предусматриваются средства для организации подпрограмм. Таким образом, программист получает возможность присвоить последовательности инструкций произвольное имя и использовать это имя в качестве сокращенной записи в тех местах, где встречается соответствующая последовательность инструкций. Подпрограмма — некоторая последовательность инструкций, которая может вызываться в нескольких местах программы.
Описание подпрограммы (функции или процедуры) состоит из двух частей: заголовка и тела. Заголовок содержит идентификатор подпрограммы. Тело состоит из одной или нескольких инструкций. Идентификатор подпрограммы используется в качестве сокращенной записи в тех местах программы, где встречается соответствующая последовательность инструкций.
Вряд ли стоило подробно говорить о столь простой форме записи, если бы за ней не скрывались важные и основополагающие понятия. В действительности процедуры и функции, называемые подпрограммами, являются одним из тех немногих фундаментальных инструментов в искусстве программирования, которые оказывают решающее влияние на стиль и качество работы программиста.
Процедура — это не только способ сокращения программного текста, но и, что более важно, средство разложения программы на логически связанные, замкнутые элементы, определяющие ее структуру. Разложение на части существенно для понимания программы, особенно если программа сложна и трудно обозрима из-за большой длины текста. Разложение на подпрограммы необходимо как для документирования, так и для верификации программы. Поэтому желательно оформлять последовательность инструкций в виде подпрограммы, даже если подпрограмма используется однократно и, следовательно, отсутствует мотив, связанный с сокращением текста программы.
Дополнительная информация о переменных (которые передаются и используются в процедуре) или об условиях, которым должны удовлетворять аргументы, задается в заголовке процедуры. О полезности процедуры, в частности о ее роли при структуризации программы, неоспоримо свидетельствуют еще два понятия в программировании. Некоторые переменные (их обычно называют вспомогательными или локальными переменными), используемые внутри процедуры, не имеют смысла за ее пределами. В программе существенно проще разобраться, если явно указаны области действия таких переменных. Процедура выступает как естественная текстовая единица, с помощью которой ограничивается область существования так называемых локальных переменных.
Вероятно, наиболее общая тактика программирования состоит в разложении процесса на отдельные действия: функционального описания на подфункции, а соответствующих программ — на отдельные инструкции. На каждом таком шаге декомпозиции нужно удостовериться, что решения частных задач приводят к решению общей задачи; выбранная последовательность отдельных действий разумна; выбранная декомпозиция позволяет получить инструкции, в каком-либо смысле более близкие к языку, на котором будет реализована программа.
Последнее требование исключает возможность прямолинейного продвижения от первоначальной постановки задачи к конечной программе, которая должна получиться в конечном итоге. Каждый этап декомпозиции сопровождается формулированием частных подпрограмм. В процессе этой работы может обнаружиться, что выбранная декомпозиция неудачна в том смысле хотя бы потому, что подпрограммы неудобно выражать с помощью имеющихся средств. В этом случае один или несколько предыдущих шагов декомпозиции следует пересмотреть заново.
Если видеть в поэтапной декомпозиции и одновременном развитии и детализации программы постепенное продвижение вглубь, то такой метод при решении задач можно охарактеризовать как нисходящий (сверху вниз). И наоборот, возможен такой подход к решению задачи, когда программист сначала изучает имеющиеся в его распоряжении вычислительную машину и/или язык программирования, а затем собирает некоторые последовательности инструкций в элементарные процедуры, типичные для решаемой задачи. Элементарные процедуры затем используются на следующем уровне иерархии процедур. Такой метод перехода от примитивных машинных команд к требуемой реализации программы называется восходящим (снизу вверх).
На практике разработку программы никогда не удается провести строго в одном направлении (сверху вниз или снизу вверх). Однако при конструировании новых алгоритмов нисходящий метод обычно доминирует. С другой стороны, при адаптации программы к несколько измененным требованиям предпочтение зачастую отдается восходящему методу.
Оба метода позволяют разрабатывать программы, которым присуща структура — свойство, отличающее их от аморфных линейных последовательностей инструкций или команд машины. И чрезвычайно важно, чтобы используемый язык в полной мере отражал эту структуру. Только тогда окончательный вид полученной программы позволит применить систематические методы верификации.
Читайте также
Понятие о стилях CSS
Понятие о стилях CSS
Для создания представления Web-страниц предназначена технология каскадных таблиц стилей (Cascading Style Sheets, CSS), или просто таблиц стилей. Таблица стилей содержит набор правил (стилей), описывающих оформление самой Web- страницы и отдельных ее фрагментов. Эти
1.4.8. Понятие о монтировании
1.4.8. Понятие о монтировании
Особого внимания заслуживает операции монтирования. На вашем жестком диске, кроме Linux-разделов, есть разделы других операционных систем (например, Windows). Для того чтобы получить доступ к файлам, находящимся в этих разделах, вам нужно
Понятие об ODS
Понятие об ODS
ODS — это аббревиатура для On-Disk Structure, т. е. структура данных баз данных InterBase на диске. ODS определяет, как организованы данные внутри файлов базы данных. Определение основных констант и структур данных для реализации On-Disk Structure находится в файле из комплекта
55. Понятие системы VВА
55. Понятие системы VВА
VBA представляет собой подмножество VB и включает средства образования приложений VB, его структуры данных и управляющие структуры, возможность создания пользовательских типов данных. Также как и VB, VBA является системой визуального программирования,
Понятие выделения
Понятие выделения
Создавая выделение, мы обозначаем в документе область, с которой хотим работать, а вся остальная часть документа для редактирования становится недоступной. Это правило справедливо для всех случаев, когда мы работаем с инструментами и командами
Понятие шаблона
Понятие шаблона
Для упрощения работы по созданию и форматированию текстов, стандартизации расположения и оформления текста, графики, типизации операций обработки документов и прочего используются шаблоны документов. Пакет Microsoft Office дает различные определения шаблона
5. Понятие индексов
5. Понятие индексов
Создание ключей в базовых отношениях автоматически связано с созданием индексов.Дадим определение понятия индекса.Индекс – это системная структура данных, в которой размещается обязательно упорядоченный перечень значений какого-либо ключа со
Понятие текстуры
Понятие текстуры
Бытует мнение, что текстура — это изображение, накладываемое на трехмерную модель. Данное утверждение совершенно не верно. Изображение, накладываемое на модель в рамках текстуры, называется картой (Map), понятие же текстуры — шире.Текстура в 3ds Max
9.1. Понятие о моделях
9.1. Понятие о моделях
Каждый объект имеет большое количество различных свойств. В процессе построения модели выделяются главные, наиболее существенные из них. Так, модель самолета должна иметь геометрическое подобие оригиналу, модель атома – правильно отражать
4.1. ПОНЯТИЕ СТРУКТУРЫ ДАННЫХ ПРОГРАММ
4.1. ПОНЯТИЕ СТРУКТУРЫ ДАННЫХ ПРОГРАММ
Под структурой данных программ в общем случае понимают множество элементов данных, множество связей между ними, а также характер их организованности.Под организованностью данных понимается продуманное устройство с целью
Понятие доверия
Понятие доверия
Новым популярным словом двадцать первого века стало слово «доверие». Доверие затрагивает многие стороны жизни людей, начиная от экономической, финансовой, деловой сфер и заканчивая принятием политических решений. Доверие требуется при приобретении
Подпрограммы
При создании
программ часто появляется некоторая последовательность команд (инструкций),
которую необходимо выполнять в нескольких местах.. Можно эту последовательность
переписать несколько раз в нужных местах, но, во
первых, это удлинит текст программы и уменьшит ее читабельность (последнее,
несомненно, хуже для программиста), но и существенно увеличит вероятность
внесения ошибок в программу. Можно попытаться обойти эту проблему с помощью GO TO. Но это потребует
дополнительной логики, реализованной с помощью флагов, что опять повышает
вероятность ошибок.
В большинстве
языков программирования для решения этой проблемы введено понятие подпрограммы (название
зависит от языка). Подпрограмма – это «кусок» кода, который вынесен из основной
программы и которому дано уникальное имя. Тогда в месте, где необходимо
выполнить эту последовательность кода, необходимо просто сослаться на имя подпрограммы. Это называется вызовом
подпрограммы (процедуры, функции,…).
Например, мы
хотим несколько раз напечатать несколько одинаковых строчек.
print *,’—————————‘
print *,’*********************‘
print *,’—————————‘
Вместо того, чтобы несколько
раз в теле программы набирать (или копировать, что несколько лучше:) эти 3
строки, можно оформить их в виде подпрограммы:
subroutine PrtSomething() ! имя подпрограммы
print *,’—————————‘
print
*,’*********************‘
print
*,’—————————‘
end
Теперь в любом месте программы, где должна
производиться соответствующая печать, нужно вызвать эту
подпрограмму по ее имени:
call PrtSomething()
Теперь усложним задачу. Нужно выполнить печать
значения разных переменных опять-таки в нескольких местах программы.
Важно запомнить одно правило: подпрограмма
НИЧЕГО не знает о том, кто и когда ее вызывает! Для нее не существует
ничего вне ее кода. Она НИЧЕГО не знает о переменных вне
ее. Можно представить ее живущей в тюремной камере без
окон. Все, что ей нужно, передается через окошечки в стене, над которыми
написано названия формальных
параметров. Подпрограммы общается с внешним
миров через ИНТЕРФЕЙС. Это правила общения подпрограммы с внешним миров. Для того, чтобы передать
какое-то значение в подпрограмму, его кладут в окошечко с названием какого-то
формального параметра. Подпрограмма берет это значение по имени формального
параметра (надпись над окошком).
Другими словами, чтобы сделать доступными какие-то
данные подпрограмме, их надо передать в списке параметров, который стоит сразу
за именем подпрограммы в скобках: subroutine PrеValues(a,b,c). Параметры,
записанные в заголовке подпрограммы, называются формальными параметрами
(аргументами). Для подпрограммы это просто
переменные. Параметры, подставленные в месте вызова подпрограммы,
называются фактическими параметрами. В качестве фактических параметров могут
быть константы, переменные или (неявные) результаты выражений.
subroutine PrеValues(a,b,c) ! имя подпрограммы
!
описание переменных – формальных параметров
integer a,b
real c
!
print *,’a= ‘,a
print *,’b= ‘,b
print
*,’c= ‘,c
return
end
В подпрограмму PrеValues(a,b,c) передаются
значения 3-х переменных, которые и печатаются. Формальные параметры – переменные,
существующие ТОЛЬКО в подпрограмме. Они ВИДНЫ ТОЛЬКО в подпрограмме. Если вне
подпрограммы есть переменные с такими же именами, они не имеют ничего общего!
Вызов этой
подпрограммы может выглядеть так:
integer a1/4/,a2/7/
real pi/3.14159/
call PrеValues(a1,a2,pi) !напечатает 4
7 3.14159
call PrеValues(1,2,7.) ! 1 2 7.
call PrеValues(1,2.,7.) ! ERROR!
При первом
вызове подпрограммы в переменную (форм. пар-ер) а будет положено значение из переменной a1(4), в b
– из a2 (7), в c – из pi (3.14…).
Соответственно подпрограмма и распечатает их в таком виде:
a=4
b=7
c=3.14159
Параметры, с
которыми вызывается подпрограмма, называются фактическими. a1,a2,pi
фактические параметры при первом вызове, 1,2,7. фактические
параметры при втором.
Почему неправильный
последний пример? Интерфейс подпрограммы предписывает, что подпрограмма ДОЛЖНА
вызываться с 3-мя фактическими параметрами, имеющими соответствующий тип.
Соответственно она и распределяет память. Если вызвать с фактическими
параметрами, имеющими другой тип, значение положится в вызывающей программе в
память по одному, а внутри подпрограммы будет взято из той-же памяти по другому. Результат становится
полностью неопределен! Отсюда вытекает следующее
правило:
Список формальных и фактических параметров должен
совпадать по количеству и характеристикам аргументов.
Другими словами, сколько параметров описано в
заголовке подпрограммы, столько же должно стоять в операторе вызова (за некоторыми исключениями),
тип и длина каждого фактического параметра должны совпадать с типом и длиной
соответствующего по порядку формального.
Параметры
могут служить не только для передачи значений внутрь подпрограммы, но и в
обратном направлении. При этом значение переменной–формального
параметра кладется в соответствующее окошко, а вызывающая сторона забирает его
и кладет в переменную – фактический параметр.
subroutine Sum(a,b,c)
real a,b,c
c=a+b
return
end
…
call Sum(1.,3.,s)
В переменную s
поместится результат сложения фактических параметров – констант 1 и 3.
Важно обратить внимание, что если формальный параметр в подпрограмме является [in] – входящим (вводящим
значение в подпрограмму), то в качестве фактического параметра может быть
переменная или константа (первые 2 параметра Sum). Если же формальный параметр в подпрограмме
является [out], или [in/out] – выходящим (возвращающем значение
из подпрограммы), то в качестве фактического параметра может быть только
переменная (3 параметр Sum).
Если подпрограмма
возвращает только одно значение, как в последнем случае, лучше использовать
другой тип подпрограмм – подпрограмму-функцию. Формально он описывается так:
FUNCTION < имя функции>(
[< форм.арг >])
< объявление форм.арг >
< объявление локальных объектов
>
…
< вычисляемые операторы,
присваивание результата >
END [ FUNCTION [ < имя функции > ] ]
Пример:
function Sum_(a,b)
real a,b,Sum_
Sum_=a+b
return
end
…
s=Sum_(1.,3.)
Результат полностью аналогичен пред.
На что надо обратить внимание:
имя функции как бы является формальным параметром, имеет тип и ему должно
быть присвоено какое-то значение. Имя функции выбрано Sum_, а не Sum, т.к. последнее часто является
зарезервированным в разных языках.
Теперь
рассмотрим задачу – составить подпрограмму нахождения мин в одномерном массиве.
Т.к. поиск мин/макс – частая задача, совершенно логично заключить ее в виде
подпрограммы-функции. Теперь об интерфейсе. Подпрограмма должна принимать в
качестве входных данных массив. Далее в цикле она будет искать мин. Но
подпрограмма не знает размер массива! Следовательно, вторым параметром надо
передать подпрограмме кол-во элементов в массиве, которые надо обработать.
program sub_min
implicit none
real a(10),min,GetMin
integer i,n
a=(/(50/i,i=1,5),(i*10,i=1,5)/) !
50.00000 25.00000 16.00000 12.00000 ! 10.00000 10.00000 20.00000 30.00000 ! 40.00000 50.00000
n=10
min=GetMin(a,n)
print *,a
print *,min
end program sub_min
real function GetMin(ar,n)
real ar(*)
integer n
GetMin=ar(n)
do n=n-1,1,-1
if (ar(n)<GetMin)
GetMin=ar(n)
end do
return
end
Тип значения, возвращаемого функцией, должен быть описан.
Для этого имя функции появляется в секции описания переменных.
В подпрограмме используется один
спорный прием. Для уменьшения кол-ва переменных в качестве переменной цикла
используется формальный параметр, через который был передан размер массива. Но
если при вызове в качестве фактич. параметра
использовалась константа (min=GetMin(a,10)), то программа
вызовет AV ошибку
обращения к памяти, т.к. внутри подпрограммы попытается положить по адресу
константы новое значение. Для надежности лучше такую «оптимизацию» не допускать. Более того, даже если при
вызове подпрограммы фактическим параметров являлась переменная, хранящее кол-во
элементов массива, то после вызова GetMin ее значение будет равно 0!
Пользователь вашей подпрограммы может ничего не знать об этом.
Как
это работает: при вызове первым параметром является массив a, вторым – размер массива. Затем
происходит переход на выполнение подпрограммы. Значения формальных переменных –
ar
– является массивом а, n
=10.
После выполнения оператора return переход обратно в
вызывающую программу. Там вместо подпрограммы уже подставляется число –
результат, который и помещается в переменную s.
min=GetMin(a(1:4),n)
Еще одно замечание: внутри
подпрограммы можно объявлять любые переменные. Но, как уже говорилось,
подпрограмма отделена от остального мира. Поэтому эти переменные существуют
только внутри подпрограммы и не видны остальному миру! Кроме того, после выхода
из подпрограммы (по оператору return или end) и повторного ее вызова значения локальных переменных
внутри подпрограммы не сохраняются. (Этого можно достичь с
помощью оператора/атрибута SAVE).
Когда использовать подпрограммы? Есть мнение, что если в какой-то программе больше 10 строк кода, то ее надо разбить на подпрограммы. Общие правила написания
структурированных, хорошо читаемых программ – если некоторый участок кода имеет
какое-то обособленное смысловое значение – выделяйте его в виде подпрограммы.
Это дает несколько преимущества: удобство чтения, уменьшение вероятности внесения
ошибок, уменьшения кол-ва переменных, удобство отладки.
Вызов подпрограмм может быть
вложенным (рис. 5). Вообще говоря, выполнение начинается с главной программы.
Во многих языках она называется MAIN.
В Fortran-е – она не
имеет названия и не имеет заголовка в отличие от всех остальных подпрограмм.
Более того, подпрограмма subroutine2 может вызвать
опять subroutine1:
………………………………
n=1
call subroutine1(n)
………………………………
subroutine subroutine1(n)
integer n
if (n<5) then
n=n+1
call subroutine2(n)
end if
return
end
subroutine subroutine2(n)
integer n
if (n<5) then
n=n+1
call subroutine1(n)
end if
return
end
рис. 5
Сведения из стандарта для справки.
Структура программы
Фортран программа состоит из одной или нескольких программных блоков (units).
Программный блок (ПБ) – это, обычно,
последовательность операторов, определяющих данные и действия, которые
необходимо предпринять для выполнения вычислений. Завершается ПБ оператором END.
ПБ может быть:
Главной программой (main program);
Внешней подпрограммой (external subprograms);
Модулем (module);
Блоком Данных (block data).
Исполняемая
программа
содержит 1 главную программу и,
возможно, любое количество любых ПБ. ПБ могут компилироваться отдельно.
Внешняя
подпрограмма
– это function или subroutine, которая не содержится внутри главной программы,
модуля, или другой подпрограммы. Она определяет алгоритм, который должен быть
выполнен, и может быть вызвана из других ПБ.
Модули и Блоки Данных не исполняемы. (Modules can contain module procedures, though, which are executable.)
Модули содержат определения,
которые могут быть сделаны доступными другим ПБ: определения типов и данных,
определения процедур (module subprograms) и
интерфейсы процедур (procedure interfaces)
Module subprograms могут быть или
functions или subroutines. Они могут быть вызваны другими module subprograms
в модуле, или другими ПБ, которые имеют доступ к модулю.
Блок данных (block data)
определяет начальные значения объектов данных в именованном common blocks. В Fortran 95/90 блок данных может быть заменен модулем.
Главная программа, внешние подпрограммы, и
подпрограммы модулей (module subprograms)
могут содержать внутренние подпрограммы (internal subprograms).
Объект, содержащий внутренние подпрограммы называется хозяином (host). Внутренние подпрограммы
могут быть вызваны только своим хозяином или другими внутренними подпрограммами
в том же хозяине. Внутренние подпрограммы не могут содержать внутри себя другие
внутренние подпрограммы (т.е. не иерархичны).
Последовательность
выполнения
Если программа содержит фортрановскую главную программу, выполнение начинается с
первой исполняемой конструкции главной программы. Выполнение любой программы
заключается в выполнении исполняемых конструкций в области программы. Когда
программы вызвана выполнение начинается
с первой исполняемой конструкции после вызванной точки входа. За исключением
приведенных ниже условий эффект выполнения как если бы исполняемые конструкции
выполняются в том порядке, в котором они записаны в программе до тех пор, пока
не будет выполнен один из операторов STOP, RETURN, or END.
Исключения:
1 – Выполнение оператора
ветвления изменяет последовательность выполнения. Эти операторы явно определяют новую точку исполнения;
2 — CASE, DO, IF, или SELECT TYPE конструкция содержит структуру внутренних
операторов, и выполнение этих конструкций приводит к неявному внутреннему
ветвлению;
3 — END=, ERR=, and EOR=
спецификаторы могут приводить к ветвлению;
4 Альтернативный Return
может приводить к ветвлению.
Внутренняя подпрограмма может
находиться до оператора END. Последовательность выполнения исключает все
подобные определения.
Нормальное прекращение
выполнения программы происходит если будет выполнен или оператор STOP или
оператор конца программы.
Встроенные функции
Оператор
безусловного перехода имеет следующий
вид: goto,
здесь
goto
— зарезервированное слово: <метка>
— метка.
Метка
— это
произвольный идентификатор, позволяющий
именовать некоторый оператор программы
и таким образом ссылаться на
него.
Можно
теоретически показать, что достаточно
if—
и
while—операторов,
чтобы
записать любую необходимую управляющую
структуру.
Однако есть несколько вполне определенных
ситуаций, где лучше использовать оператор
goto.
Первая
состоит в том, что многие циклы не могут
завершаться в
точке входа, как этого требует цикл
while.
Вторая
ситуация, которую легко запрограммировать
с помощью
goto,
— выход
из глубоко вложенного вычисления.
Например, если
глубоко внутри вызовов процедур
обнаружена ошибка, что делает
неверным все вычисление. В этой ситуации
естественно запрограммировать
выдачу сообщения об ошибке и возвратить
в исходное
состояние все вычисление. Однако для
этого требуется сделать возврат из
многих процедур, которые должны знать,
что произошла
ошибка. Проще и понятнее выйти в основную
программу с
помощью goto.
В
языке С
нет
никаких средств для обработки этой
ситуации (не
подходит даже goto
по
причине ограниченности рамками отдельной
процедуры), поэтому для обработки
серьезных ошибок нужно
использовать средства операционной
системы.
В
современных языках Object
Pascal,
Ada,
C++ и
Eiffel
есть
специальные
языковые конструкции, так называемые
исключения, которые
непосредственно решают и эту проблему.
2.5. Подпрограммы. Процедуры и функции
Часто
некоторую последовательность инструкций
требуется
повторить в нескольких местах программы.
Чтобы программисту
не приходилось тратить время и усилия
на копирование этих инструкций, в
большинстве языков программирования
предусматриваются средства для
организации подпрограмм. Таким образом,
программист получает возможность
присвоить последовательности
инструкций произвольное имя и использовать
это имя в
качестве сокращенной записи в тех
местах, где встречается соответствующая
последовательность инструкций.
Подпрограмма
— некоторая
последовательность инструкций, которая
может повторяться в нескольких местах
программы.
Процедурой
называется
особым образом оформленный фрагмент
программы, имеющий собственное имя
(идентификатор), который выполняет
некоторую четко определенную операцию
над данными, определяемыми параметрами.
Упоминание
имени процедуры в тексте программы
приводит к
ее активизации и называется вызовом
процедуры. Вызов может быть осуществлен
из любой точки программы. При каждом
таком вызове
могут пересылаться различные параметры.
Сразу после активизации процедуры
начинают выполняться входящие в нее
операторы, после выполнения последнего
из них управление возвращается
обратно в основную программу, и выполняются
операторы, стоящие
непосредственно за оператором вызова
процедуры.
Описание
процедуры состоит из заголовка и тела.
Заголовок процедуры
имеет вид:
procedure
<имя> [ (<сп.ф.п.>) ] ;
здесь
<имя> имя процедуры (правильный
идентификатор); <сп.
ф. п. > — список формальных параметров.
Список
формальных параметров необязателен и
может отсутствовать.
Если же он есть, то в нем должны быть
перечислены имена формальных
параметров и их типы, например procedure
MyProc
(a:
Real;
b:
Integer;
с: Char);
Функция
отличается
от процедуры тем, что результат ее работы
возвращается
в виде значения этой функции, и,
следовательно, идентификатор
функции может использоваться наряду с
другими операндами
в выражениях. Описание функции состоит
из заголовка и тела. Заголовок функции
имеет следующий вид:
function
<имя>
[(<сп.ф.п.>)]:
<тип>;
здесь
<тип> — тип возвращаемого функцией
результата. Заголовок
функции может иметь следующий вид:
function
MyFunc (a,
b: Real): Real;
Операторы
тела подпрограммы рассматривают список
формальных
параметров как своеобразное расширение
раздела описаний:
все переменные из этого списка могут
использоваться в любых
выражениях внутри подпрограммы. Так
осуществляется настройка
алгоритма подпрограммы на конкретную
задачу. Работа с
процедурами и функциями отличаются в
следующем:
-
в
заголовке функции помимо описания
формальных параметров
обязательно указывается тип возвращаемого
ею результата; -
для
возврата функцией значения в точку
вызова среди ее операторов
должен быть хотя бы один, в котором
имени функции или
переменной Result
присваивается
значение результата; -
вызов
процедуры выполняется отдельным
оператором; -
вызов
функции может выполняться там, где
допускается ставить
выражение, например, в правой части
оператора присваивания.
Соседние файлы в предмете Программирование
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Создать из обычной программы распределенную программу легче, если эта обычная программа состоит из компонент. Во-первых, она уже разделена на функциональные части, которые могут располагаться вдали друг от друга. Во-вторых, поскольку компоненты заменяемы, вместо некоторой компоненты можно подставить другую, единственной задачей которой будет обеспечивать связь с удаленной компонентой.
Преимущества использования компонент непосредственно вытекают из способности последних подключаться к приложению и отключаться от него. Для этого компоненты должны удовлетворять двум требованиям. Во-первых, они должны компоноваться динамически. Во-вторых, должны скрывать (или инкапсулировать) детали своей реализации.
Чтобы понять, как это связано с инкапсуляцией, необходимо определить некоторые термины. Программа или компонента, использующая другую компоненту, называется клиентом (client). Клиент подсоединяется к компоненте через интерфейс (interface). Если компонента изменяется без изменения интерфейса, то изменений в клиенте не потребуется. Аналогично если клиент изменяется без изменения интерфейса, то нет необходимости изменять компоненту. Однако если изменение либо клиента, либо компоненты вызывает изменение интерфейса, то и другую сторону интерфейса также необходимо изменить.
Таким образом, для того чтобы воспользоваться преимуществами динамической компоновки, компоненты и клиенты должны стараться не изменять свои интерфейсы и быть инкапсулирующими. Детали реализации клиента или компоненты не должны отражаться в интерфейсе. Чем надежнее интерфейс изолирован от реализации, тем менее вероятно, что он изменится при модификации клиента или компоненты. Если интерфейс не изменяется, то изменение компоненты оказывает лишь незначительное влияние на приложение в целом.
Необходимость изоляции клиента от деталей реализации накладывает на компоненты ряд важных ограничений, список которых приведен ниже.
Ограничение 1. Компонента должна скрывать используемый язык программирования. Компоненты могут быть разработаны с помощью практически любого процедурного языка, включая Ada, С, Java, Modula-3, Oberon и Pascal. Любой язык, в том числе Smalltalk и Visual Basic, можно приспособить к использованию компонент СОМ. Любой клиент должен иметь возможность использовать компоненту независимо от языков программирования, на которых написаны тот и другой.
Ограничение 2. Компоненты должны распространяться в двоичной форме. Действительно, поскольку они должны скрывать язык реализации, их необходимо поставлять уже откомпилированными и готовыми к использованию (DLL).
Ограничение 3. Компоненты СОМ можно модернизировать, не нарушая работы старых клиентов. СОМ предоставляет стандартный способ реализации разных версий компонент. Новые версии компонент должны работать как с новыми клиентами, так и старыми.
Ограничение 4. Компоненты СОМ являются перемещаемыми по сети, причем перемещаемость по сети должна быть прозрачной. Компонента на удаленной системе рассматривается так же, как компонента на локальном компьютере. Необходимо, чтобы компонента и использующая ее программа могли выполняться внутри одного процесса, в разных процессах или на разных машинах. Клиент должен рассматривать удаленную компоненту так же, как локальную. Если бы с удаленными компонентами надо было бы работать иначе, чем с локальными, то потребовалось бы перекомпиляция клиента всякий раз, когда локальная компонента перемещается в другое место сети.
Пользователь может иметь два клиентских приложения, использующих одну и ту же компоненту. Предположим, что одно приложение применяет новую версию этой компоненты, а другое — старую. Установка новой версии не должна нарушать работу приложения, которое использовало старую версию. Старое приложение использует новую компоненту vi абсолютно так же, как это делает новое (рис. 6.2).
Однако обратная совместимость не должна ограничивать развитие компонент. Нужно, чтобы поведение компоненты для новых приложений можно было радикально изменять, не нарушая поддержку старых приложений.
Рис. 6.2. Поэтапное получение новых приложений
Таким образом, технология предусматривает взаимозаменяемость компонент во время выполнения посредством установления стандарта, которому должны следовать компоненты; практически прозрачной поддержки нескольких версий компоненты; обеспечения возможности работы со сходными компонентами одинаковым способом; определения архитектуры, независимой от языка; поддержки прозрачных связей с удаленными компонентами.
ВЫВОДЫ
• Разработка архитектуры — это процесс разбиения большой системы на более мелкие части. Процесс разработки архитектуры — этап, необходимый при проектировании систем или комплексов, но необязательный при создании программы. Если внешние спецификации (экранные формы, организация файлов…) описывают программную систему с точки зрения пользователя, то следующий шаг проектирования состоит в разработке архитектуры, а за ним следует проектирование структуры каждой программы.
• Программная система может состоять из отдельных, разработанных разными организациями выполняемых программ; из программ, обменивающихся данными через порты; из отдельных резидентных программ.
• Традиционно программа проектировалась из отдельных файлов, модулей или классов, которые компилировались и компоновались в единое целое.
• Разработка программ из компонент — так называемых приложений компонентной архитектуры — происходит совершенно иначе. С появлением технологии разработки развивающихся и рассредоточенных (многомашинных) комплексов программ, основанной на модели компонентных объектов (СОМ), единого целого больше нет: программы состоят из отдельных компонент. Компонента поставляется пользователю как двоичный код, скомпилированный, скомпонованный и готовый к использованию. Доступ к этому коду осуществляется через точно документированный интерфейс. Во время выполнения компоненты подключаются к другим компонентам, формируя программу.
Контрольные вопросы
1. Что такое архитектура программ?
2. Являются ли синонимами понятия «структура» и «архитектура»?
3. В чем заключается процесс разработки архитектуры программы?
4. Как реализуется архитектура системы из отдельных программ?
5. Что такое резидентная программа?
6. Как осуществляется обмен данными через порты?
7. Перечислите принципы подхода к проектированию архитектуры системы с позиции уровней абстракции Дейкстры.
8. Почему из обычной программы создать распределенную программу легче, если она состоит из компонент?
9. Перечислите ряд ограничений, которые накладываются на компоненты.
10. Посредством чего предусматривается взаимозаменяемость компонент?
Глава 7
ТЕХНОЛОГИЯ СТРУКТУРНОГО ПРОГРАММИРОВАНИЯ
7.1. ПОНЯТИЕ СТРУКТУРЫ ПРОГРАММЫ
Структура программы — искусственно выделенные программистом взаимодействующие части программы. Использование рациональной структуры устраняет проблему сложности разработки; делает программу понятной людям; повышает надежность работы программы при сокращении срока ее тестирования и сроков разработки вообще.
Часто некоторую последовательность инструкций требуется повторить в нескольких местах программы. Чтобы программисту не приходилось тратить время и усилия на копирование этих инструкций, в большинстве языков программирования предусматриваются средства для организации подпрограмм. Таким образом, программист получает возможность присвоить последовательности инструкций произвольное имя и использовать это имя в качестве сокращенной записи в тех местах, где встречается соответствующая последовательность инструкций. Подпрограмма — некоторая последовательность инструкций, которая может вызываться в нескольких местах программы.

