3.3. Конкретные примеры

В предыдущих обсуждениях мы изложили начальные сведения, необходимые для понимания структуры и семантики задач, создаваемых на языке Ада. В данном разделе мы рассмотрим фрагменты конкретных примеров, полностью приведенных в приложении Е. В этом приложении дается написанная на языке Ада задача Portfolio_Server и части спецификации задачи Roster_Server и пакета Membership_Roster. Эти программные единицы созданы в соответствии со структурой, приведенной на рис. 2.5. [В приложении В приводятся соответствующие программные единицы для структуры на рис. 3.2.]

В программной структуре, приведенной на рис. 2.5, задача Portfolio_Server перегружена рядом избыточных "ответственностей". Она должна осуществлять ряд обращений к Roster_Server. Помимо этого она должна преобразовывать запросы оператора к Club_Portfolio. Такая зависимость Roster_Server от Portfolio_Server, независимого самого по себе от Membership_Roster, уже достаточна для того, чтобы отказаться от стратегии, реализуемой в структуре, приведенной на рис. 2.5. Читатели, имеющие больший опыт в параллельном программировании, наверняка с этим уже согласились. Однако в целях упражнения мы продолжим рассмотрение и анализ структуры программы, реализующей подход, приведенный на рис. 2.5.

Тип входа Имя входа
Запросы к портфелю (9).
(Выполняются как обращения
к операциям пакета
Club_Portfolio.)
Print_Club_portfolio
Print_Club_holdings
Find_stock_code
Print_individual_stock_summary
Print_shares_and_value_of_stock
Print_average_cost
Print_winners
Print-loosers
Print_non_movers
Запросы на обновление портфеля (2).
(Выполняются как обращения к
операциям пакета Club_Portfolio
после обращений к Roster_Server.)
Enter-buy
Enter_sell
Запросы на создание и удаление
портфеля (6).
(Выполняются как обращения к
операциям в Club_Portfolio после
обращений к Roster_Server.)
President_create_folio
Vice_president_create_folio
Treasurer_create_folio
President_delete_folio
Vice-president_delete_folio
Treasurer_delete_folio
Запросы к Membership_Roster (2).
(Выполняются через обращения к
Roster-Server.)
Lookup-member
List_of_members
Обновления Membership-Roster (3).
(Выполняется через обращения к
Roster-Server.)
Add-new-member
Update_member
Delete-member
Рис. 3.8. 22 отдельных входа Portfolio-Server, используемых в структуре, приведенной на рис. 2.5.

На рис. 3.8 приводится список входов, необходимых для задачи Portfolio_Server. Каждый из этих входов требует объявления entry в части спецификации программы Portfolio_Server.

Как видно из рис. 2.5, Portfolio_Server непосредственно зависит от спецификаций для Roster_Server и для Club_Portfolio. В свою очередь Roster_Server зависит от спецификаций для пакета Membership_Roster.

Удобно продолжить развитие Portfolio_Server с расширения спецификации Membership_Roster, а затем спецификации Roster_Server, закончив, наконец, расширением спецификации Portfolio_Server. Эта последовательность и определила список на рис. 3.8. [Вспомните, что мы уже модифицировали пакет Club_Portfolio (см. приложение В). Помните, что модификации этого пакета были сделаны с целью введения двух дополнительных операций - Delete_folio и Create_folio.]

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

with Roster_Types_And_Constants, Text_I0;
package Membership_Roster is
   use Roster_Types_And_Constants, Text_I0;
   type roster is private;       -- см. определение ниже.
--
-- Имеются пять следующих операций (см. приложение Е):
-- Lookup_member,      -- Возвращает копию записи текущего сотрудника,
-- List_of_members,    -- Печатает список информации из журнала.
-- Add_new_member,     -- Добавляет запись о новом сотруднике.
-- Update_member,      -- Обновляет запись о текущем сотруднике.
-- Delete_member       -- Удаляет запись о текущем сотруднике.
--
private
   type roster is array (1 .. max_num_members) of member_record;
   --
   -- (Предполагается, что) экземпляр списка порождается в
   -- теле данного пакета.
end Membership_Roster;

   Рис. 3.9. Скелетная структура спецификации пакета Membership_Roster.

Пять операций пакета Membership_Roster поясняются в комментариях к рис. 3.9. При успешной работе каждая из операций выполняет указанную функцию. Читатель может посмотреть полную спецификацию этих операций в приложении Е.

Отметим, что приватный тип списка зависит от константы max_num_members и от типа member_record. Эти два элемента объявляются в дополнительном пакете Roster_Types_And_Constants, который появляется в операторных скобках with и use Membership_Roster. Позднее мы увидим, что Roster_Server и Portfolio_Server также зависят от Roster_Types_And_Constants. Эта зависимость объясняется ниже.

Задача Roster_Server имеет пять объявлений входа. Эти объявления перечислены на рис. 3.10.

Тип входа Имя входа
Запросы о занимаемых должностях,
являющимися булевскими (4) функциями.
(Выполняются через обращения к
Membership_Roster.)
Is_president
Is_vice_president
Is_treasurer
Is_secretary
Общие запросы к списку (2).
(Выполняются через обращения к
Membership_Roster.)
Lookup_member
List_of_members
Запросы на обновление списка членов
организации (3). (Выполняются через
обращения к Membership_Roster.)
Add_new_member
Update_member
Delete_member
Рис. 3.10. 9 индивидуальных входов для Roster_Server, используемых в структуре на рис. 2.5.

Задаче Roster_Server необходимо иметь доступ к представлению типа member_record, поскольку ей требуется давать ответ на запросы о занимаемых должностях. Для этого в своем ответе на полученный вызов от Membership_Roster. Lookup_member эта задача должна быть способна анализировать индивидуальные компоненты экземпляра member_record. В процессе выполнения запросов на обновленре журнала задачи Roster_Server и Portfolio_Server направляют индивидуальные записи member_record к Membership_Roster. По этой причине тип member_record не может быть объявлен приватным.

with Membership, Roster, Roster_Types_And_Constants;
task Roster_Server is
   use Membership_Roster, Roster_Types_And_Constants;
--
-- Запросы занимаемых должностей;
--
   entry Is_President(
      mennber_name: in  string_of30;
      check:        out boolean);
   --
   -- Функция:
   -- Обращается к Membership_roster. Lookup_member для получения записи
   -- о member_name (от имени члена организации). Устанавливает значение
   -- в true, если member_name соответствует имени члена организации, чье
   -- имя есть President, в противном случае возвращается прежнее значение
   -- false.
   
   entry Is_Vice_President(
      member_name: in  string_of30;
      check:       out boolean);
   --
   -- Функция:
   -- Аналогична функции Is_President.

-- Здесь размещается вход для Is_treasurer.
-- Здесь размещается вход для ls_secretary.
--
-- Общие запросы к списку:
--
-- Здесь размещается вход для Lookup_member.
-- Здесь размещается вход для List_of_members.
--
-- Запросы на обновление списка членов организации:
--
-- Здесь размещается вход для Add_new_member.
-- Здесь размещается вход для Update_member.

   entry Delete_member(
      my_name:     in  string_of30;
      member_name: in  string_of30;
      check:       out boolean);
   --
   -- Функция:
   -- Вызывает Membership_Roster.Delete_member для удаления всей информации
   -- о текущем сотруднике из списка членов организации. Если удаление прошло
   -- успешно, то перед возвратом в переменную check устанавливается true.
   -- В переменную check устанавливается false, если обращение к Delete_member
   -- закончилось неудачно. (Это может произойти в том случае, когда значение
   -- переменной my_name не соответствует имени секретаря или если в списке
   -- еще нет сотрудника с таким именем.)
end Roster_Server;

        Рис. 3.11. Скелетная структура части спецификации Roster_Server.

На рис. 3.11 приведена скелетная форма части спецификации задачи Roster_Server, в которой приводятся подробности для трех из девяти входов. Полный набор входов рассматривается в приложении Е.

with Club_Portfolio, Roster_Server,
     Stock_Types_And_Constants,
     Roster, Types_And_Constants;
           -- На рис. 2.5 и 3.2 были показаны не все из этих зависимостей.

task Portfolio_Server is
   use Club_Portfolio, Roster_Server,
       Stock_Types_And_Constants, Roster_Types_And Constants;
--
-- Здесь производятся запросы к портфелю (9 входов).
--
-- Запросы на обновление портфеля:
   entry Enter_buy(
      my_name:      in  string_of30;
      unauthorized: out boolean;
      purch_date:   in  date;
      stock_code:   in  stock_code_pair;
      num_shares:   in  natural;
      per_sh_price: in  dollars;
      commission:   in  dollars);
--
-- Функция;
-- Определяет, имеет ли сотрудник с именем, указанным в переменной my_name,
-- право на обновление портфеля. Если нет, то в переменную unauthorized
-- устанавливается и возвращается значение true. Если да, то в unauthorized
-- подcтавляется false и затем вызывается соответствующая операция в
-- Club_Portfolio.
--
-- Здесь располагается вход для Enter_sell.
--
------------ Здесь помещаются операции по обслуживанию запросов на создание
--           и удаление портфеля (6 входов).
--
------------ Запросы к списку членов организации (5 входов).
--
end Portfolio_Server;

    Рис. 3.12. Скелетная структура спецификации Portfolio_Server
               с входом Enter_buy

Использование входов Portfolio_Server иллюстрируется в рассмотрении протокола по обновлению и удалению портфеля. На рис. 3.12 дано извлечение из части спецификации Portfolio_Server для входа Enter_buy. На рис. 3.13 в части тела Portfolio_Server показан соответствующий оператор accept.

accept Enter_buy(
   my_name:      in  string_of30;
   unauthorized: out boolean;
   purch_date:   in  date;
   stock_code:   in  stock_code_pair;
   num_shares:   in  natural;
   per_sh_price: in  dollars;
   commission:   in  dollars);
do
   Roster_Server.Is_treasurer(my_name, check_boolean);
   if check_boolean then    -- санкционированный
      Club_Portfolio.Enter_buy(purch_date,
                               stock_code,
                               num_shares,
                               per_sh_price,
                               commission);
      unauthorized:= false;
   else
      unauthorized:=true;
   end if;
end Enter_buy;

    Рис. 3.13. Иллюстрация того, каким образом оператор accept для Enter_buy  
               обусловливает обращение к Roster_Server.Is_Treasurer

Первые два параметра для Enter_buy являются управляющими. В переменной my_name должно быть указано имя обращающегося к данной программе. Это имя должно совпадать с именем казначея организации. Параметр unauthorized возвращает значение "true", если указанное имя сотрудника организации, проверенное по входу Is_treasurer для Roster_Server, не соответствует имени казначея. С такой спецификацией для входа Enter_buy тело соответствующего оператора accept для Enter_buy (см. рис. 3.13) начинается с обращения ко входу Is_treasurer. Если этот вызов устанавливает локальную переменную check_boolean в "true", то после последующего обращения к операции Enter_buy в Club_Portfolio значение unathorized устанавливается в "false". В противном случае оно устанавливается в "true".

entry President_delete_folio(
   my_name:        in  string_of30;
   portfolio_name: in  long_string;
   unauthorized:   out boolean);
--
-- Функция:
-- Вызывает Roster_Server для определения того, является ли сотрудник со
-- значением имени my_name текущим президентом организации. Если это не
-- так, то в переменную unauthorized устанавливается значение true. Если это
-- так, то в переменную unauthorized устанавливается значение false и затем
-- это значение возвращается после записи указанного имени портфеля.
-- Фактиеское удаление не произойдет до тех пор, пока не будет получена
-- последовательноеть из трех запросов на удаление, по одному на каждого из
-- трех членов администрации организации: президента, вице-президента
-- и казначея.

     Рис. 3.14. Объявление входа для первого из трех обращений
                по удалению портфеля.
                

entry Vice_president_delete_folio(
   my name:        in  string_of30;
   portfolio_name: in  long_string;
   unautliorized:  out boolean);
--
-- Функция:
-- Запрос к данному входу воспринимается в том и только в том случае, если
-- последнее воспринятое обращение было сделано ко входу
-- President_delete_folio и это обращение было санкционированным.
-- Определяет, является ли в данный момент сотрудник с именем, значение
-- которого содержится в переменной my_name, вице-президентом организации.
-- Если это не так, то в переменную unauthorized устанавливается значение
-- true. Если это так, то в переменную unauthorized устанавливается значение
-- false и затем это значение возвращается после записи указанного имени
-- портфеля. Фактическое удаление не произойдет до тех пор, пока не будет
-- получена последовательность из трех запросов на удаление, по одному на
-- каждого из трех членов администрации организации: президента,
-- вице-президента и казначея.

    Рис. 3.15. Объявление входа для второго из трех вызовов
               для удаления портфеля.


entry Treasurer_delete_folio(
   my name:        in  string_of30;
   portfolio-name: in  long_string;
   unauthorized:   out boolean; 
   check:          out boolean);
                 -- если установлена в true, то портфель был удален.
--
-- Функция:
-- Обращение к данному входу принимается в том и только в том случае, если
-- два последних воспринятых обращения были произведены к
-- President_delete_folio и к Vice_president_delete_folio в указанном
-- порядке и если оба этих запроса были санкционированными.
-- Вызывает Roster_Server для определения того, является ли сотрудник
-- с именем, значение которого содержится в переменной my_name,
-- текущим казначеем клуба.
-- Если это не так, то в переменную unauthorized устанавливается значение true
-- и это значение возвращается. Если это так, то в переменную unauthorized
-- устанавливается значение false. Три указанных имени проверяются. Если все
-- они не идентичны, то в переменную check устанавливается значение false и
-- производнтся возврат.
-- Если они совпадают, то из Club_Portfolio вызывается операция Delete_folio.
-- Если вызов успешный (портфель удаляется), то в переменную check
-- устанавливается значение true. Затем происходит возврат к вызвавшему
-- Treasurer_delete_folio.

       Рис. 3.16. Объявление входа для третьего из трех вызовов
                  по удалению портфеля.


accept President_delete_folio(
   my name:        in  string_of30;
   portfolio_name: in  long_string; 
   unauthorized:   out boolean)
do
   Roster_Server.Is_treasurer(my_name, check_boolean)
   if check_boolean then
      local_name_1:=portfolio_name;    -- Сохранить копию portfolio_name
                                       -- для проверки при следующем accept.
      unauthorized:=false;
   else
      unauthorized:=true;
   end if;
end President_delete_folio;
--
-- Здесь начинается последовательность из двух операторов accept.
--
accept Vice_president_delete_folio(
   my name:        in  string_of30;
   portfolio_name: in  long_string;
   unauthorized:   out boolean)
do
   Roster_Server.Is_vice_president(my_name, check_boolean)
   if check_boolean and local_name_1=portfolio_name then
      lосаl_name_2:=portfolio_name;   -- Сохранить копию portfolio_name для
                                      -- проверки при следующем accept.
      unauthorized:=false;
   else
      unauthorized:=true;
   end if;
end Vice_president_delete_folio;
--
accept Treasurer_delete_folio(
   my name:        in  string_of30;
   portfolio_name: in  long_string;
   unauthorized:   out boolean;
   check:          out boolean);
                     -- если установлена в true, то портфель был удален.
do
   Roster_Server.Is_treasurer(my_name, check_boolean)
   if check_boolean and local_name_1=portfolio_name
                    and local_name_2=portfolio_name then
      unauthorized:=false;        --Доступ разрешен.
      Club.Portfolio.Delete_folio(portfolio_name, check);
                      -- Портфель был удален, если значение, возвращенное в
                      -- переменной check есть true.
   else
      unauthorized:=true;
   end if;
end Treasurer_delete_folio;
--
-- Конец последовательности (конец последовательности из трех операторов
-- accept).

    Рис. 3.17. Последовательность из трех операторов accept,
               которая должна быть выполнена для удаления элемента
               экземпляра портфеля.

Последний пример в данном разделе иллюстрирует три операции, необходимые для удаления портфеля. На рис. 3.14≈3.16 приведен набор из трех объявлений входа в Portfolio_Server, к которым для завершения процедуры удаления портфеля должно быть произведено обращение. На рис. 3.17 показана соответствующая последовательность трех операторов accept для части тела Portfolio_Server. Комментарии, предлагаемые для трех объявлений входа в Portfolio_Server, должны убедить читателя в том, что приводимая последовательность операторов accept в точности отражает эти спецификации.

назад оглавление вперед
Рейтинг ресурсов "Весь Екатеринбург"