В предыдущих обсуждениях мы изложили начальные сведения, необходимые для понимания структуры и семантики задач, создаваемых на языке Ада. В данном разделе мы рассмотрим фрагменты конкретных примеров, полностью приведенных в приложении Е. В этом приложении дается написанная на языке Ада задача 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 приводится список входов, необходимых для задачи 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 |
Задаче 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 в точности отражает эти спецификации.
![]() |
![]() |
![]() |