Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
62
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 59

Крупные проекты

Глава 59 Крупные проекты

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

О модулях и разделении труда

Пока я возился с новой программкой, мой холодильник опустел, а на кухне скопилась немытая посуда. Впрочем, это пустяки в сравнении с заботами наших предков — крестьян, что жили сотни лет назад. Смотрите: вот мужик в окружении десятка голодных ртов, а там ещё князь с дружиной. И всех накорми, одень, согрей. А делать всё самому: пахать и сеять, избу рубить, ткать, шить и лапти плести. Эта морока называлась натуральным хозяйством.

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

Взять хотя бы производство автомобиля — не самого сложного изделия по нынешним временам. А сколько народу копошится вокруг! Автомобильные заводы грандиозны, хотя здесь лишь собирают машины из частей, что делают на других заводах. Части сложных изделий называют узлами или модулями. Модуль — это часть изделия, которую можно изготовить и проверить отдельно от целого. Сборка изделий из модулей дала и высокое качество товара, и бешеную производительность труда. Так новые технологии породили и роскошные машины, и свободное время, убиваемое нами в автомобильных пробках.

Говорят, что история повторяется, ведь с технологиями программирования случилось то же самое, но гораздо быстрее. Ещё полвека назад одну программу мастерил один человек, — то была эпоха первых компьютеров и «натурального хозяйства» в программировании. По мере развития компьютеров росли и аппетиты пользователей, усложнялись решаемые задачи. Сообразно задачам усложнялись программы, и производство их в одиночку стало немыслимо. Потребовались разделение труда и специализация программистов, — точь-в-точь как в промышленности. И теперь производством сложных программ заняты программистские «фабрики».

Так что же это такое, технологии программирования? Алгоритмы какие-то? Или сверхсильные компьютеры? Нет, технологии — это орудия труда и средства его разумной организации. В чем они состоят применительно к нашему ремеслу?

480

Глава 59

Крупные проекты

Модули

Вам срочно потребовалась новая программа? Так призовите больше программистов и пусть они трудятся разом! Легко сказать, но как это сделать? Могут ли три писателя сразу сочинять один роман? Первый строчит начало, второй

— середину, а третий — окончание? Или три художника писать одну картину? Но в программировании такое возможно! — выручает модульная организация программ.

В Паскале, как и в других современных языках, большой программный проект можно разбить на ряд частей — модулей (UNIT). Модули могут быть написаны и отлажены разными программистами на разных компьютерах независимо друг от друга, а затем соединены в одну программу. В этом и состоит модульное программирование.

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

Дробление модуля – «смертельный» номер

Рассмотрим заурядный случай. Положим, вы работаете над проектом строк эдак на пятьсот, что составляет десяток страниц печатного текста. Немалая часть вашей программы — процедуры, функции — уже отлажена, проверена и может пригодиться в других работах. Файл программы «разбух», и потому работать с ним неудобно. К чему эти готовые куски маячат перед глазами и мешают рыться в проблемных частях? Зреет здравая мысль: а не вынести ли их куда-нибудь в другой файл? Но так, чтобы связь с ними, не терялась. А потом, при необходимости, воспользоваться этими кусками в других проектах. Эти разумные мысли ведут вас к модульному программированию.

Сейчас мы разобьем на модули одну из наших программ. Нужен «доброволец», пусть им будет программа P_56_1. Мы распилим её на две части, как дамочку в цирке. Не пугайтесь, — программа, как и дамочка, останется живёхонька и здоровёхонька. Напомню, что P_56_1 — это шуточная программа для перестановки строк файла в обратном порядке. Вот её схема, где тела процедур я заменил многоточиями, а часть комментариев удалил. Для экономии места дальше я буду показывать программу схематично.

481

Глава 59

Крупные проекты

{P_56_1 – перестановка строк файла } type PRec = ^TRec;

TRec = record mStr : string; mNext : PRec;

end;

var Stack : PRec; { Голова стека } procedure Push(const arg : string);

{. . . }

end;

function Pop(var arg : string): boolean;

{. . . } end;

{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } var F : text; S : string;

begin

{---

Главная программа ---}

{ . . . }

end.

Вероятно, средства для работы со стеком пригодятся нам где-то ещё, и есть смысл сохранить их на складе. Разделим программу на две части. Первую часть, до пунктирной линии — подпрограммы Push, Pop, объявление типа и переменную Stack — скопируем в другой файл и назовем его MyLibr.pas — моя библиотека. Сохраним её в папке с нашими программами. Здесь вам пригодится умение работать с несколькими окнами и держать открытыми оба файла.

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

{ P_59_1 – Первичный файл проекта } var F : text; S : string;

begin

{--- Главная программа ---}

{ . . . }

 

end.

 

Файл с главной программой называют первичным (Primary), стало быть, P_59_1 — это первичный файл нашего проекта. Будет ли он компилироваться? Ясно, что нет. Ведь там вызываются удаленные из файла процедура и функция. Надо подсказать компилятору, что они переехали в файл MyLibr. Для такой переадресации служит список импорта, который возглавляет ключевое слово USES. Пользоваться списком импорта легко, — достаточно поместить его в начале программы, перечислив после слова USES имена нужных модулей (несколько имен

482

Глава 59

Крупные проекты

разделяются запятыми). В нашем случае внешним модулем является файл MyLibr, поэтому дополненный списком импорта первичный файл станет таким.

{ P_59_1 – Первичный файл проекта }

uses

MyLibr;

{ импортируемый модуль }

var F : text;

S : string;

begin

{--- Главная программа ---}

{ . . . }

 

end.

 

 

Как видите, расширение файла в списке USES не указывают, а сам список завершает точка с запятой. Теперь всё, что компилятор не найдет в основной программе, он будет искать в файле MyLibr. Говорят, что первичный файл импортирует модуль MyLibr. Компилируется такой проект из двух файлов как обычно — нажатием клавиши F9. Впрочем, для успешной компиляции время ещё не пришло.

Теперь обратимся к файлу MyLibr. На первый взгляд он содержит всё нужное для компиляции, но это не так. Ведь это не программа, а лишь часть её — модуль. Файлу надо придать особую форму — форму библиотечного модуля, что достигается вставкой в него четырех обязательных ключевых слов (ниже они подчеркнуты).

unit MyLibr;

{

имя библиотечного

модуля }

interface

{

секция интерфейса

}

{. . .} {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

implementation { секция реализации }

{. . .}

end.

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

Но открывает файл ключевое слово UNIT (модуль), — оно назначает модулю имя. Имя указывают за словом UNIT через пробел, эта строка завершается точкой с запятой. Имя модуля должно совпадать с именем файла, но без расширения PAS. Впрочем, имя может быть и длиннее — до 63-х символов, но первые восемь из них должны повторять имя файла. Итак, присвойте модулю имя MyLibr.

Следующие два ключевых слова: INTERFACE (интерфейс) и IMPLEMENTATION (реализация) делят модуль на две части. Эти части так и называются: секция интерфейса и секция реализации. Важно правильно расставить эти ключевые слова. Кстати, точка с запятой за ними не ставится!

483

Глава 59

Крупные проекты

Начнем с секции реализации, хотя по порядку она идет второй. Эта секция должна вмещать всё (или почти всё), что требуется для работы модуля: объявления типов, констант, переменных, а также процедуры и функции. И потому в неё сейчас свалим то, что перетащили из основной программы. Итак, слово IMPLEMENTATION мы поставим перед описанием типов, и в результате библиотечный файл станет таким.

unit MyLibr;

{

имя библиотечного

модуля }

interface

{

секция интерфейса

}

{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

implementation { секция реализации }

type PRec = ^TRec; TRec = record

mStr : string; mNext : PRec;

end;

var Stack : PRec; { Голова стека } procedure Push(const arg : string);

{. . . } end;

function Pop(var arg : string): boolean;

{. . . }

end;

end.

Теперь обратимся к секции интерфейса. Хотя слово INTERFACE уже на месте, но секция пока пуста. Каково её назначение? Здесь пора рассказать о видимости объектов, размещенных в модуле. Точнее, о видимости их за пределами этого модуля. Оказывается, что всё, помещенное нами в секцию реализации, невидимо извне, скрыто от посторонних глаз. Так устроено по причинам, которые мы обсудим позже. Но для компиляции проекта надо приоткрыть часть модуля внешнему миру, иначе из главной программы (которая проживает в другом файле) не будут видны нужные ей идентификаторы библиотечного модуля. Для этого и нужна секция интерфейса.

На обозрение выставим только идентификаторы, нужные внешним модулям. Что именно? Как это узнать? Самый верный способ — запустить компиляцию первичного модуля, и тогда компилятор покажет первый незнакомый идентификатор, — его описание и разместим в секции интерфейса. Повторная компиляция выявит следующий неизвестный идентификатор. Так постепенно мы обнаружим, что первичный модуль нуждается в переменной Stack, процедуре Push и функции Pop. Впрочем, вам это было и так ясно.

484

Глава 59

Крупные проекты

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

unit MyLibr;

{ имя библиотечного модуля }

 

interface

{ секция интерфейса }

 

type PRec = ^TRec;

 

TRec = record

 

mStr

: string;

 

mNext : PRec;

 

end;

 

 

var Stack : PRec; { Голова стека }

 

procedure Push(const arg : string);

{ заголовок процедуры }

function Pop(var arg : string): boolean;

{ заголовок функции }

{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

implementation { секция реализации }

procedure Push(const arg : string); { . . . }

end;

function Pop(var arg : string): boolean; { . . . }

end;

end.

Описание типа и переменная Stack объявлены лишь один раз — в секции интерфейса, отсюда они видны как внутри, так и вне библиотечного модуля. Повторное их объявление в секции реализации будет ошибкой. Заголовки процедур и функций в секциях интерфейса и реализации должны совпадать. Но в секции реализации разрешено не повторять списки параметров, и тогда компилятор возьмет их из секции интерфейса.

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

485

Соседние файлы в папке delphi