дб. Четвертое издание джозеф Джарратано Университет Хьюстон клиэрЛэйк Гари Райли People5oft, Издательский дом "Вильямс" Москва СанктПетербург Киев 2007 ббк 32. 973. 26 018 75 Д
Скачать 3.73 Mb.
|
11.8. Обработчики сообщений, определяемые пользователем В данном определении терм представленное термом (defmessage-handler CIRCLE compute-area () (* (pi) (send ?self get-radius) (send ?self get-radius))) (definstances figures (rectangle- 1 of RECTANGLE (height 2) (width 4)) (circle-1 of CIRCLE (radius 3))) В данном примере определяются два класса, RECTANGLE и, с соответствующими слотами. За каждым классом закреплен обработчик сообщений compute-area. Этот обработчик сообщений предназначен для вычисления пло- Глава 11. Классы, экземпляры и обработчики сообщений Здесь заслуживает внимания то, что каждому экземпляру передается одно и тоже сообщение, но, вычисляя площадь фигуры, заданной сего помощью, каждый экземпляр отвечает по-разному. Такая способность различных экземпляров отвечать на одно и тоже сообщение в характерной для него форме называется полиморфизмом. Сокращенные ссылки на слоты Если бы всегда приходилось передавать экземпляру сообщения для выборки или установки значения любого слота, то при написании многих программ возникали бы значительные неудобства, поэтому предусмотрен сокращенный механизм, позволяющий получить доступ к любым слотам экземпляра, связанного с переменной ? self. Таким образом, вместо применения следующего выражения (send ?self для выборки значения слота можно использовать выражение ? self: возведенное в квадрат. Обратите внимание на то, что в обоих обработчиках сообщений используется переменная ?self. Это специальная переменная, автоматически определяемая для каждого обработчика сообщений. При вызове обработчика сообщений переменной ? self присваивается значение адреса того экземпляра, которому передается сообщение. Эта переменная может применяться для передачи в экземпляр сообщений, как и было сделано в рассматриваемом примере для выборки значений слотов height, width и radius. После определения обработчиков сообщений появляется возможность отправлять сообщения compute — area в экземпляры классов и CIRCLE для получения информации о площади фигуры, заданной этим экземпляром, как в следующем примере (reset)J CLIPS> (send [circle-1] compute-area)J 28.2743338823081 CLIPS> (send [rectangle-1] compute-area)J 8 CLIPS> 11.8. Обработчики сообщений, определяемые пользователем Например, описанные выше обработчики сообщений compute — area можно переопределить следующим образом RECTANGLE compute-area () (* ?self:height ? self:width)) (defmessage-handler CIRCLE compute-area () (* (pi) ? self:radius ?self:radius)) Аналогичный механизм может применяться для задания значения слота. Вместо такого выражения (send ?self put- предположим, что заданы две следующие конструкции de f class: (defclass A (а USER) (slot x)) (defclass В (а Ау) В таком случае приведенный ниже диалог показывает, что сокращенную ссылку можно использовать лишь для того, чтобы сослаться на слоту, а не на слот х в обработчике сообщений для класса В (defmessage-handler В bmh1 () (* 2 ?self:z))J [NSGFUN6] Private slot x of class А cannot be accessed directly by handlers attached to class В [PRCCODE3] Undefined variable х referenced in message-handler. ERROR: 886 Глава 11. Классы, экземпляры и обработчики сообщений В bmhl () (* 2 х) ) CLIPS> (defmessage-handler В bmh2 () (* 2 ?self:y))J CLIPS> В обработчике сообщений bmh1 создается ссылка на переменную ? sel f: ха это недопустимо, поскольку слот х унаследован от класса А. В обработчике сообщений bmh2 разрешается сделать ссылку на переменную ? self: у, поскольку слоту определен в классе В. В языке COOL поддерживается инкапсуляция объектов, а это означает, что детали реализации класса скрываются от постороннего взгляда и доступ к классу ограничивается вполне определенным интерфейсом обработчиками сообщений, определенными для данного класса. Поскольку интерфейсом для выборки значений слотах из экземпляров класса A является обработчик сообщений get — х, то в обработчике сообщений bmh1 и должен использоваться этот интерфейс. С учетом такой поправки обработчик сообщений bmhl может быть безошибочно определен следующим образом CLIPS> (defmessage-handler В bmh1 () (* 2 (send ?self get-x)))J CLIPS> Такой принцип действия слота, обеспечивающий инкапсуляцию, можно отменить с использованием атрибута слота visibility. Если этому атрибуту присваивается значение private, предусмотренное по умолчанию, то непосредственный доступ к слоту может осуществляться только в обработчиках сообщений класса, определяющего этот слот. А если данному атрибуту присвоено значение public, ток слоту может быть получен непосредственный доступ в подклассах и суперклассах любого определяющего его класса. В частности, в предыдущем примере применение следующего определения класса А (defclass Ах) позволяет определить обработчик сообщений bmhl таким образом (defmessage-handler В bmh1 () (* 2 х. Обработчики сообщений, определяемые пользователем Отслеживание процесса передачи сообщений и функционирования обработчиков сообщений При отслеживании сообщений или обработчиков сообщений с использование команды watch с параметром messages или message — handlers каждый раз, после того как начинается и заканчивается выполнение кода обработчика сообщений или начинается и заканчивается передача сообщений, выводится информационное сообщение CLIPS> (watch messages)J CLIPS> (watch message-handlers)J CLIPS> (send [circle-1] compute-area)J MSG » compute-area ED:1 ( compute-area primary in class CIRCLE ED:1 ( MSG « compute-area ED:1 ( CLIPS> (send [rectangle-1] compute-area)J MSG » compute-area ED:1 ( RECTANGLE ED:1 ( compute-area ED:1 ( handlers отслеживается функционирование обработчиков сообщений, то отладочная информация выводится после того, как начинается и заканчивается выполнение кода каждого конкретного обработчика сообщений. При отслеживании функционирования обработчиков сообщений предоставляется вся та информация, которая может быть получена при отслеживании сообщений, а также некоторая дополнительная информация. В приведенном выше диалоге информационные сообщения, выводимые в результате отслеживания сообщений, обозначались префиксом MSG, а информация, полученная при отслеживании функционирования обработчиков сообщений, отмечалась префиксом HND. Символ » свидетельствует об инициализации отслеживания определенного со Глава 11. Классы, экземпляры и обработчики сообщений общения или обработчика сообщений, а символ « — о завершении отслеживания конкретного сообщения или обработчика сообщений. За символом » или « следует имя сообщения или обработчика сообщений. В современной версии языка вслед за именем обработчика сообщений предусматривается вывод некоторой дополнительной информации обозначение типа обработчика сообщений (Ьейоге, аЙ1ег, primary или around), за которым следует имя класса, связанного сданным конкретным функционирующим обработчиком сообщений. Одно-единственное сообщение способно вызвать на выполнение многочисленные обработчики сообщений различных типов или классов, поэтому данная информация позволяет определить, какой из них фактически функционирует. В последнюю очередь отображается фрагмент информации, показывающий глубину вложенности вызовов, обозначаемый символом ED, за которым следуют параметры, передаваемые обработчику сообщений. Как и при использовании конструкций бей, глубина вложенности вызовов позволяет определить, насколько глубоко вложены вызовы конструкций de f function и вызовы обработчиков сообщений. Отсчет глубины вложенности вызовов начинается с нуля, и после каждой передачи управления очередной конструкции de f function или обработчику сообщений глубина увеличивается на единицу. После выхода из каждой конструкции def function или из обработчика сообщений значение глубины вложенности уменьшается на единицу. В списке параметров в первую очередь всегда указывается параметр, представляющий собой значение переменной ? self. После этого перечисляются все явно заданные параметры обработчика сообщений. Возможно также обеспечить отслеживание функционирования сразу всех обработчиков сообщений конкретного класса, указав имя этого класса для отслеживания функционирования конкретного обработчика сообщений необходимо задать только имя класса и обработчика сообщений для отслеживания функционирования конкретного обработчика сообщений определенного типа необходимо указать класс, имя обработчика сообщений, а после этого тип (Ьейоге, айег, primary или around): CLIPS> (unwatch all)J CLIPS> (watch message-handlers CIRCLE)J CLIPS> (watch message-handlers RECTANGLE compute-area)J CLIPS> (watch message-handlers RECTANGLE get-height primary)J CLIPS> Первая команда watch обеспечивает отслеживание функционирования всех обработчиков сообщений, определяемых пользователем и системой для класса CIRCLE. Вторая команда watch обеспечивает отслеживание функционирования обработчика сообщений compute — area типа primary для класса RECTANGLE 11.8. Обработчики сообщений, определяемые пользователем (и обеспечивала бы отслеживание функционирования обработчиков сообщений типа ай1ег, before и around, если бы они были определены. Третья команда watch отслеживает функционирование только определяемого системой обработчика типа primary для класса RECTANGLE. КОМИНДЫ бе ййе З ЗаЯе-handler Для манипулирования конструкциями de fmes sage — handler предусмотрено несколько команд. Для отображения текущего списка конструкций de f me s s a— ge — handlers, поддерживаемых системой CLIPS, служит команда list-defmessage-handlers. Эта команда имеет следующий синтаксис (list-defmessage-handlers [ put-height primary in class RECTANGLE get-width primary in class RECTANGLE put-width primary in class RECTANGLE compute-area primary in class RECTANGLE For а total of 5 message-handlers. CLIPS> (ppdefmessage-handler |