Объектно-ориентированные средства в CLIPS
На примере обработчика сообщения rack вы можете убедиться в справедливости нашего замечания о том, что обработку данных внутри объекта нужно поручать методам этого объекта, а не включать прямо в правило.
(defmessage-handler pistol rack () (if (> (dynamic-get rounds) 0) then (dynamic-put chamber 1) (dynamic-put rounds (– (dynamic-get rounds) 1)) (dynamic-put slide forward) else (dynamic-put chamber 0) (dynamic-put slide back)
В этом обработчике обеспечивается досылка патрона в патронник в том случае, если в обойме имеются патроны. Следующее правило подготавливает пистолет к стрельбе, снимая его с предохранителя. Обратите внимание на то, что в нем повторно используется сообщение safety, но на этот раз с аргументом off.
(defrule ready (object (name [PPK]) (chamber 1)) › (send [PPK] safety off))
Правило fire выполняет стрельбу.
(defrule fire (object (name [PPK]) (safety off); ?T ← (range-test (fired no)) › (if (eq (send [PPK] fire) TRUE) then (modify?T (fired yes))))
Обратите внимание, что в данном правиле используется обработчик сообщения, которое возвращает значение. Анализируя его, можно выяснить, произведен ли выстрел, т.е. выполнена ли в действительности та операция, которая "закреплена" за этим сообщением. Если в патроннике был патрон и пистолет был снят с предохранителя, то обработчик сообщения вернет значение TRUE (после того, как выведет на экран BANG!). В противном случае он вернет FALSE (после того, как выведет на экран click).
(def message-handler pistol fire () (if (and (eq (dynamic-get chamber) 1) (eq (dynamic-get safety) off) ) then (printout t crlf "BANG!" t crlf) TRUE else (printout t crlf "click" t crlf) FALSE )
Пусть вас не смущает, что в обработчике сообщения анализируется условие, которое уже было проанализировано правилом, отославшим сообщение (в данном случае речь идет об условии safety off). Дело в том, что одно и то же сообщение может отсылаться разными правилами и нет никакой гарантии, что в каждом из них будет проверяться это условие.
После завершения стрельбы пистолет нужно вновь вернуть в положение "по-походному". Начинается это с того, что пистолет устанавливается на предохранитель, для чего используется ранее разработанный обработчик сообщения safety.
(defrule unready (object (name [PPK]) (safety off)) (range-test (fired yes)) › (send [PPK] safety on))
Следующая операция – вынуть обойму. Обратите внимание, что в нем мы вновь обращается к обработчику сообщения drop.
(defrule drop (object (name [PPK]) (safety on)) (range-test (fired yes)) › (send [PPK] drop))
Последнее правило выбрасывает патрон из патронника, вызывая обработчик сообщения clear.
(defrule unload (object (name [PPK]) (safety on) (magazine out)) (range-test (fired yes)) › (send [PPK] clear))
В этом примере было продемонстрировано, как в рамках единой CLIPS программы "уживаются" правила и объекты. Правила управляют ходом вычислений, но некоторые операции объекты выполняют и самостоятельно, получив "указание" (сообщение) от правил. Объекты не являются резидентами рабочей памяти, но члены левой части правил (условий) могут быть сопоставлены с содержимым их слотов.
Состояние объектов может измениться и вследствие побочных эффектов активизации правил, но я считаю, что лучше предоставить объектам возможность самостоятельно выполнять манипуляции с хранящимися в них данными в ответ на поступающие от правил сообщения. Объекты не могут самостоятельно активизировать правила, но их обработчики сообщения могут возвращать определенную информацию о результатах, которая используется для управления логикой выполнения действий в правой части правил.