Шаг 110.
Структура модуля и назначение его разделов

    На этом шаге мы рассмотрим структуру модуля.

    Используя модули важно правильно указывать их имена. При подключении стандартных модулей достаточно корректно записать их идентификаторы в предложении uses.

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

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

unit <ИдентификаторМодуля>;
{Интерфейсный раздел.} 
interface
    { В этом разделе описывается     взаимодействие  }
    { данного модуля  с  другими  пользовательскими  }
    { и  стандартными модулями,  а  также с  главной }
    { программой.   Другими  словами -    взаимодей- }
    { ствие  модуля  с   "внешним миром".            }
{Список импорта интерфейсного раздела. } 
uses
    {   В  этом списке  через  запятые  перечисляются }
    {   идентификаторы модулей,   информация интер-   }
    {   фейсных  частей  которых  должна  быть  дос-  }
    {   тупна  в  данном модуле.                      }
    {   Здесь   целесообразно  описывать идентифика-  }
    {   торы     только  тех модулей, информация  из  }
    {   которых используется  в   описаниях раздела   }
    {   interface данного модуля.                     }
{ Список экспорта интерфейсного раздела.}
const      { Список  экспорта  состоит из  подраз-   }
type       { делов     описания    констант, типов,  }
var        { переменных, заголовков  процедур и      }
procedure  { функций, которые определены в дан-      }
function   { ном модуле, но  использовать кото-      }
                   { рые разрешено во всех других моду- }
                   { лях и  программах,  включающих имя }
                   { данного модуля в своей строке uses.}
                   { Для процедур и функций здесь  опи- }
                   { сываются  только  заголовки,  но с }
                   { обязательным полным описанием фор- }
                   { мальных параметров.                }
{  Раздел реализации.  } 
implementation
               { В этом разделе указывается реализацион-     }
               { ная (личная) часть описаний данного моду-   }
               { ля, которая недоступна для других модулей   }
               { и программ. Другими словами - "внутренняя   }
               { кухня" модуля.                              }
{  Список импорта раздела реализации.  } 
uses
               { В этом списке через запятые перечисляются }
               { идентификаторы модулей, информация интер- }
               { фейсных частей которых должна быть дос-   }
               { тупна в данном модуле.                    }
               { Здесь целесообразно описывать идентифика- }
               { торы всех необходимых модулей, информа-   }
               { ция из которых не используется в описани- }
               { ях раздела Interface данного модуля и об  }
               { использовании которых не должен знать ни  }
               { один другой модуль.                       }
{ Подразделы внутренних для модуля описаний. }
label      { В этих подразделах описываются мет-}
const      { ки, константы,  типы,  переменные, }
type       { процедуры и функции, которые описы-}
var        { вают алгоритмические действия, вы- }
procedure  { полняемые данным модулем, и которые}
function   { являются  "личной  собственностью" }
                 { исключительно только данного моду- }
                 { ля. Эти описания недоступны ни од- }
                 { ному  другому модулю.  Заголовки   }
                 { процедур и функций в этом подраз-  }
                 { деле  допускается  указывать   без }
                 { списка формальных параметров. Если }
                 { заголовки указаны все же  с  пара- }
                 { метрами, то  список формальных па- }
                 { раметров должен быть идентичен та- }
                 { кому же списку для соответствующей }
                 { процедуры   (функции)   в разделе  }
                 { interface.                         }
{Раздел инициализации. } 
initialization
                { В этом разделе между зарезервированными словами     } 
                { initialization и finalization располагаются one-    } 
                { раторы начальных установок, необходимых для запуска } 
                { корректной работы модуля.                           }
                { Операторы разделов инициализации модулей, используе-}
                { мых в программе, выполняются при начальном запуске  }
                { программы в том же порядке, в каком идентификаторы  }
                { модулей описаны в предложениях uses. Если операторы }
                { инициализации  не   требуются,то зарезервированное  }
                { слово initialization может быть опущено.            }
finalization
                {Раздел  завершения  finalization является  необя-   }
                {зательным и может  присутствовать только  вместе  с }
                {разделом инициализации initialization.   В разделе  }
                {завершения располагается список операторов, которые }
                {будут  выполняться при завершении модуля, что обычно}
                {происходит  при окончании работы приложения. Разделы}
                {finalization модулей  приложения  выполняются  в    }
                {порядке,   противоположном выполнению разделов      }
                {initialization этих модулей.   Раздел  завершения   }
                {используется как правило для освобождения ресурсов, }
                {выделенных приложению в разделе инициализации и тем }
                {самым гарантирует корректное "чистое"  завершение   }
                {приложения. Особенно это важно в  случаях,   когда  }
                {приложение  заканчивается  по  возникновению        }
                {исключительных  ситуаций.                           }
end.

    В Object Pascal для обозначения раздела инициализации модуля используется зарезервированное слово initialization, в отличие от версии Borland (Turbo) Pascal, в которой применялось слово begin. В принципе, использование слова begin также допускается (совместимость с предыдущими версиями поддерживается), но не рекомендуется.

    Раздел finalization является нововведением языка Object Pascal, реализованной начиная с Delphi 2.0. Этот раздел отсутствовал как в Borland (Turbo) Pascal, так и 16-тиразрядной версии .


    При работе с модулями необходимо помнить их основное отличие от процедур и функций.

    Традиционные правила сферы действия глобальных и локальных переменных для модулей не работают. Языковая конструкция "модуль" была специально разработана, чтобы исключить влияние глобальных переменных, объявленных в главной программе, на внутренние описания модуля.

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

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

unit UGlob;
{  Модуль глобальных описаний  }
interface
type
  TVal = Integer;
    { Чтобы не загромождать пример излишними деталями, для }
    { описания глобального типа TVal сделано простейшее }
    { переопределение типа. }
implementation

end.
unit UStack;
{ Библиотечный модуль, включающий сервисные }
{ процедуры и функции для работы со списковой }
{ структурой типа "стек". }

interface
{ Список импортируемых модулей . }
uses UGlob;   { Достаточно указать только модуль  }
              { UGlob, т.к. в описаниях раздела   }
              { interface информация из  других   }
              { стандартных и пользовательских мо-}
              { дулей не используется. Модули,    }
              { описанные в interface, будут дос- }
              { тупны также и в implementation.   }

 {  Список экспортируемых процедур. }
procedure Push (Val : TVal) ;
 {Процедура занесения элемента в стек. }

procedure Pop (var Val : TVal) ;
  {Процедура извлечения элемента из стека. }

function GetStatus : string;
  {Функция, возвращающая строку состояния стека. }

implementation

{Список "личного" импорта модуля. }

{ uses . . . ; Подключение других модулей в разделе  }
{ implementation для реализации UStack               }
{ не требуется. Хотя информация из модуля            }
{ UGlob используется в implementation,               }
{ указывать его в этом списке  недопустимо, т.к.     }
{ описанный в нем тип TVal используется в заго-      }
{ ловках процедур Push и Pop и каждый модуль может   }
{ быть указан только один раз  - или в interface,    }
{ или в implementation. Модули, описываемые в        }
{ разделе implementation, в принципе допускается     }
{ подключать в разделе interface. Однако это         }
{ считается  плохим  стилем написания модулей,       }
{ т.к.  информация из этих модулей в описаниях       }
{ раздела interface не используется.                 }

type
 TPtr  = ^TElem;  { Тип указателя на элемент стека. }
 TElem = record   { Тип элемента стека. }
           Inf  : TVal;
           Link : TPtr
         end;
var
  Top : TPtr;   { Указатель на верхушку стека.      }
  Value : TVal; { Переменная для очистки стека      }
                { в разделе finalization.           }
  i : Byte;     { Переменная для организации цикла. }

{ !!! Заголовки процедур и функций, которые уже }
{ !!! описаны в разделе  interface,  в  разделе }
{ !!! реализации можно указывать без параметров.}
procedure Push;
var
  P : TPtr;
begin
  New (P);
  P^.Inf := Val;
  P^.Link := Top;
  Top := P
end;

procedure Pop;
var
  P : TPtr;
begin
  if Top <> nil then
  begin
    Val := Top^.Inf;
    P   := Top;
    Top := P^.Link;
    Dispose (P)
  end
end;

function GetStatus;
var
  S, El : string;
procedure PrintEl(P : TPtr);
{ Внутренняя для модуля  процедура,  выполняющая }
{ печать элементов стека. }
{ Заголовки процедур и функций, которые в разделе interface}
{ не экспортируются, в разделе implementation описываются  }
{ всегда  полностью (с параметрами) .                      }
begin
  if P <> nil then
  begin
    PrintEl (P^.Link);
    Str(P^.Inf:3, El);
    S := S + El;
  end;
end;
begin
  S := '';
  PrintEl(Top);
  GetStatus := S;
end;

initialization
  {Начальная установка  верхушки  стека.   }
  Top := nil;
  {Создание  исходной  конфигурации  стека из 10-ти  элементов.}
  for i := 1 to 10 do Push(i);
finalization
  {Завершающая  очистка  памяти,   занимаемой  стеком,     }
  {независимо  от  того,   в  каком состоянии он  остался  }
  {после использования  в других модулях.                  }
   while Top <> nil  do  Pop (Value);

end.
unit UseStack;
{Модуль UseStack использует  стек, }
{реализованный  в модуле  UStack.  }
interface

uses
{Информация из  перечисленных  стандартных модулей исполь-        }
{зуется для  описания  экспортируемых модулем UseStack            }
{ формы Form1  и  ее  типа  TForm1.   Поэтому  компилятор  Delphi }
{подключает их  в разделе  interface,   а  не  в разделе          }
{implementation.                                                  }
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
UGlob, UStack;
{ Модули UGlob и UStack, описываемые в разделе          }
{ implementation, в принципе можно было бы подключить и }
{ в разделе interface. Однако это считается плохим      }
{ стилем написания модулей,  т.к. информация из этих    }
{ модулей в описаниях раздела interface не используется.}


procedure TForm1.Button1Click(Sender: TObject);
{ По щелчку на кнопке Buttonl заносит }
{ случайное число в стек. }
var
  Val : TVal;
begin
  Val := Random(10);
  Push(Val);
end;


procedure TForm1.Button2Click(Sender: TObject);
{ По щелчку на кнопке Button2 удаляет }
{ верхний элемент стека. }
var
  Val : TVal;
begin
  Pop(Val)
end;


procedure TForm1.Button3Click(Sender: TObject);
{ По щелчку на кнопке Button3 выводит }
{ состояние стека в поле Edit1. }
begin
  Edit1.Text := GetStatus;
end;

initialization
  { При запуске проекта инициализирует }
  { генератор случайных чисел. }
  Randomize;
end.
Текст этого примера можно взять здесь.

    Результат работы приложения показан на рисунке 1:


Рис.1. Результат работы приложения

    Со следующего шага мы начнем знакомиться с динамически подключаемыми библиотеками.




Предыдущий шаг Содержание Следующий шаг