Матросов А.В. Maple 6. Решение задач высшей математики и механики (1185909), страница 62
Текст из файла (страница 62)
В описательной части модуля, кроме уже знакомых нам по процедурам операторов объявления локальных (1ооа1) и глобальных (о1оьа1) переменных, опций (ортьоп) и строки описания (бевотьрттоп), может использоваться оператор ехротс, объявляющий экспортируемые переменные модуля. Все перечисленные операторы, за исключением последнего, полностью соответствуют их аналогам, используемым при объявлении процедур (разве лишь модули поддерживают несколько иной набор опций), а вот оператор ехротс имеет исключительно важное значение лля конструкции модуль. В этом операторе описываются имена переменных и процедур, которые модуль экспортирует во внешнюю среду.
По существу они также являются локальными, но в отличие от переменных из оператора 1 а1 становятся доступными пользователю. Чтобы получить доступ к экспортируемым именам модуля, называемым еше его членами, следует использовать специальную операцию ":-" выбора члена модуля. После "имени" модуля, соответствующего имени переменной, которой присваивается объект модуль, задается последовательность символов ":-", за которой следует экспортируемое имя. В примере 5.26 объявляется модуль и вызывается его процедура пес () для получения значения локальной переменной модуля.
:;:Юфтей(ф3ф$ й(~))с((ВФЬ,',Ф-~6~()~М())~ф!)$~3~йФь~й~~~ффф)т)(()Ф(Ь1фМЕЯГФИ а;; > Ч:=пюба1е() ехротт чет) 1оса1 1ос," 1ос с=в) дес: ртос () 1оо) епб ртос) ееб спосЬл1е; в.= тподп1еб )оса) )ос; ехрон лет( епб тподп1е > ч:-лет(); > д:-1оо; Еттот, пюба1е боев псе ехротт '1ос' КаК ВИдИтЕ, ПОПЫтКа ПОЛуЧЕНИя ЗНаЧЕНИя ЛОКаЛЬНОй ПЕрЕМЕННОй 1оо МОдуля оказалась не успешной, тогда как обращение к экспортируемой процеду- рЕ Оет(), ВОЗВраШаЮШЕЙ ЗНаЧЕНИЕ ЛОКаЛЬИОй ПЕрЕМЕННОй 1оо, ПрИВЕЛа К нужному результату. Более того, можно включить в модуль экспортируемую ззз Глава б Основы программирования а Мар(е процедуру, которая будет изменять значение этой же локальной переменной модуля, т.
е. таким образом можно реализовать инкапсуляцию. При вычислении в Мар!е определения модуля создается объект модуль, который можно мыслить как набор его экспортируемых имен, часто называемых членами модуля. В теле модуля экспортируемым именам, которые могут представлять переменные и процедуры, можно присваивать начальные значения и объявления процедур, в которых используются локальные переменные модуля. Кюкдое очередное вычисление определения модуля создает отдельный экземпляр модуля, инициирует его локальные и экспортируемые переменные, а также создает отдельный набор локальных переменных. В примере 5.27 определение модуля задано в процедуре део(), вызов которой создает новый экземпляр модуля.
Экспортируемым именем является единственная локальная переменная е модуля. В каждом экземпляре модуля она своя, поэтому логическая операция сравнения одной и той же локальНОй ПЕрЕМЕННОй дВуХ ЭКЗЕМПЛярОВ МОдупя ЗаВЕРШаЕтСя ВЫЧИСЛЕНИЕМ Ге1ее. > г:=росс() пооо1е() ехрогг ег епдг Г.= ргосП соодп1еЦ ехрог( е; епд гаодп!е епд ргос > д:=г() г е .'= сооде1еП ехрогс е; епд сподп1е > 1:=Г() ! .= гаодп1еП ехрогг е; епд гаодп!е > д:-е) > 1:-е( > ееа1Ь(д: — е = 1:-е) „Га!ге > ега1Ь(е = 1: — е) .Га(ге Экспортируемая модулем локальная переменная не то же самое, что и глобаль- ная переменная с таким же именем (см.
последний оператор примера 5.27). Замечание Модули и процедуры можно свободно вкладывать друг в друга. Глубина уровня вложенности может быть произвольной. Часть!. Основы Мар)о 334 Модуль отличается от процедуры тем, что, во-первых, он не содержит формальных параметров, а во-вторых, вычисление объявления модуля одновременно "инициирует" его, создавая набор локальных и экспортируемых переменных.
Вычисление объявления процедуры только "создает" в памяти "описание" процедуры, а все ее локальные переменные созлаются и вычисляются каждый раз при ее вызове. Правда, с помошью процедур можно также организовать доступ к локальным переменным, используя возврашаемую процедурой процедуру (см.
пример 5.28). > д:=ргос) ) 1оса1 1ос,десг 1ост=в) дест ргос() 1осг еос)) осс) ргос; я:= ргосй!осп! /ос, лен )ос:= 5; яе);= ргосП )ос епг) ргос епл ргос > г:=д()) 1:= ргосй!ос епд ргос > г))г В процедуре примера 5.28 используется небольшой "трюк". Локальная переменная 1ос вычисляется при инициировании вызова процедуры д)), возвращаемым значением которой является локальная процедура до) и, которая, В СВОЮ ОЧЕрЕдЬ, ВОЗВраШаЕт ЗНаЧЕНИЕ ЛОКаЛЬНОй ПЕрЕМЕННОй тос. НО так как после вызова процедуры д() ее локальная переменная деш) становится видимой и вне тела процедуры, то становится видимой и ее локальная ПсрЕМЕННая 1ос. Для определения экспортируемых имен модуля предназначена команда охрогсе)), единственным параметром которой является имя объекта модуль: > ехрогсв (д) ) В приведенной команде определяются экспортируемые имена модуля примера 5.26.
Для проверки, является ли некоторое имя членом, т. е. экспортируемым именем, некоторого модуля можно использовать уже известную нам функ- цИЮ пегеЬог (): > геогеьег(дес, д) ) впе 335 Глава в Основы программн валия в Мар(о > вепЬег(1ос, 9) г Га(зе В объявлении модуля нет никаких формальных параметров, так как модуль, в отличие от процедуры, не "вызывается", а поэтому и нет необходимости в передаче фактических параметров.
Однако каждое объявление модуля имеет НЕЯВНЫИ ПаРаМЕтР ГЬ1звсбп1е, КОтОРЫй аНаЛОГИЧЕН ПараМЕтрУ ргсспа е ПрО- цедуры, но отличается от последнего. Параметр ргоспаве вычисляется как имя процедуры, тогда как параметр гь1звобп1е вычисляется как сам модуль. Это позволяет создавать разные имена для одного и того же объекта, экспортируя процедуру, возвращающую сам модуль (пример 5.29). > в:= вобп1е () ехрогс запеМобп1е,депсо1ог, зеГСс1ог; 1аса1 Со1ог; Со1сг:="В1ие"г деГСо1сг: =ртос () Со1ог епб ргосг зеГСа1сг:=ргос(х::втгьпд) Со1от:=х; епб ргсс; вапенсбп1е := ртос() ГП1звобп1е епб ртос; епб воби1е: > В:-9ЕГСС1от() ГВ:-ЗЕГСС1ст('гаЕб") (В:-датсс1ОГ() ( "В)пе" "Кеб" "Кеб" > д:=в:-запемобп1е(); и .= гоода1еО 1оса! Со!ог; отрог( тате)г(сг(и)е, яеКо)ог. зе(Го(ог: еаб таоба)е > д:-деГСо1от(); "Кед" > в:-зетсс1от(тте11он")гд:-детсо1ст(); "уе!!огпп ете!1отп > д: -зеГСо1ог (пн1аск" ) Гв:-деГСо1ог (); "В! ас(с" "В!асЕ" Часть( Основы Мвр/е В примере 5.29 создан модуль ~п, члены которого депсо1ог)) и аетсо1оп)) соответственно читают и устанавливают значение локальной переменной со1от, а член аатпемобо1е<) возвращает объявление самого модуля.
Если переменной д присвоить результат выполнения процедуры аатеиобо1е)), то ссылаться на первоначально созданный объект модуль с именем и можно и по имени д, причем любые изменения локальных переменных с помощью методов объекта и влияют, естественно, и на значения локальных переменных объекта д, и наоборот. Это как раз и подтверждает тот факт, что оба имени ссылаются на один и тот же обьект. Мар1Е раСПОЗНаЕт МОдуЛЬ КаК тИП С ИМЕНЕМ пюбо1е. Тах КаК СаМО СЛОВО тобо1е ЯВЛЯЕтся КлЮчевым словом, то в комаНде пронерКИ тИПа ЕГо СЛедУет заключать в обратные кавычки пхх)о1е". > д:=тпобо1е)) ехрого 1; 1:=От еоб тобо1е: > суре)д, 'пюбо1е') т ттие > суре йтеапл1де)>па, 'тпобо1е') ) ттие > туре)11па1д,'вобо1е') „та)ее ОбратИтЕ ВНИМаНИЕ, ЧтО НОВЫЙ ПаКЕт ЛИНЕйНОй аЛГЕбрЫ Ьаоеатд1де)тпа рЕаЛИЗОВаи В ВИДЕ МОДУЛЯ, тОГДа КаК СтаРЫй ПаКЕт 1)оа1д МОДУЛЕМ НЕ ЯВЛЯЕТСЯ. Завершая краткий разговор о модулях Мар!е, мы приведем простой пример, демонстрирующий их применение.
Очень полезным при реализации разнообразных динамических структур данных является объект, который хранит пару связанных значений. Именно его мы и попробуем реализовать. Прежде чем создавать любой объект, его следует "спроектировать", т. е. определить его состояние и поведение. Состояние программного объекта реализуется в локальных переменных модуля, а поведение, или что может "делать" объект, задается экспортируемыми процедурами. В нашем случае связанной пары некоторых значений объект должен, естественно, хранить эти значения (мы их реализуем в локальных переменных г1пап и ееооаб), позволять получать их, а также допускать их независимое изменение. Поведение объекта представим четырьмя экспортируемыми процедурами: первые две (депг1пап ) ) и аестдтеп 1) ) будут, соответственно, возвращать и устанавливать первое значение связанной пары, а вторые две (депзеоооб)) И аесаесопб ) ) ) выПоЛнять аналогиЧНЫЕ дЕйстВия дЛЯ второго зкачеНиЯ связанной пары.
Для создания объекта необходим конструктор, представляющий процедуру, которая возвращает объявление модуля, реализующего обьект. Параметрами процедуры должны быть первое и второе значения связанной пары. Реализация конструктора представлена в примере 5.30. Глава б. Основы программирования в Мар)в > НакеРаьт: = ртос ( а, Ь) дюбс1е () 1оса1 Г1твт, зесопб) ехротт детгтгвт, деГЯесопб, веггтгзт, яетзесопб: Г1твт := а) зесопб := Ь) детг1тяг := () -> г1тяг) детэесопб :=.
() -> зесопб; зеггггзг := ртос( т) т1тяг := т епб) веГЯесопб := ргос( т) яесопб ;= т епб) епб пюбп1е епб ртос: Теперь можно создать объект, представляющий связанную пару значений, с помощью разработанного конструктора и проверить правильность работы экспортируемых процедур; > Р1: — —.нахеРа1т(х, у): > Р1;-детггтят(), Р1:-детяесопс(() ) НУ > Р1;-вегвьгзг(пю)) Р1:-дегзагвг(),щ:-дегяесопб(); )г Однако постоянно вызывать методы созданного объекта Ра с использованием операции ссылки на члены модуля: — не достаточно эффективно с точки зрения читаемости программы. Изменить эту ситуацию можно, создав общие процедуры вызова методов объектов.