Объектно-ориентированные средства в CLIPS
Использование объектно-ориентированных средств в CLIPS позволяет значительно упростить программирование правил, поскольку для обновления данных можно применять механизм передачи и обработки сообщений методами классов. В этом разделе мы продемонстрируем, как это делается на примере, который моделирует правила обращения с полуавтоматическим пистолетом.
Первым делом определим класс pistol, в котором будут перечислены свойства, необходимые для моделирования.
(defclass pistol (is-a USER) (role concrete) (pattern-match reactive) (slot safety (type SYMBOL) (create-accessor read-write)) (slot slide (type SYMBOL) (create-accessor read-write)) (slot hammer (type SYMBOL) (create-accessor read-write)) (slot chamber (type INTEGER) (create-accessor read-write)) (slot magazine (type SYMBOL) (create-accessor read-write)) (slot rounds (type INTEGER) (create-accessor read-write)))
Первые три слота – системные. Они нужны объектно-ориентированной надстройке CLIPS (COOL – CLIPS object-oriented language). Эти слоты COOL извещают о том, что:
- pistol – это пользовательский класс;
- pistol является конкретным классом, т.е. возможно создание экземпляров этого класса (альтернативный тип – абстрактный класс, который играет ту же роль, что и виртуальный класс в C++);
- экземпляры класса pistol могут быть использованы в качестве объектов данных, которые можно сопоставлять с условиями в правилах и использовать в действиях, определенных правилами.
Следующие пять слотов представляют свойства и члены данных класса:
- слот safety (предохранитель) может содержать символ on или off;
- слот slide (затвор) может содержать значение forward или back, т.е. хранит информацию о положении затвора;
- слот hammer (курок) содержит информацию о состоянии курка, back или down;
- слот chamber (патронник) содержит значение 1 или 0, в зависимости от того, есть ли патрон в патроннике;
- слот magazine (обойма) может содержать значение in или out, в зависимости от того, вставлена ли обойма;
- слот rounds (патроны) содержит текущее количество патронов в обойме.
Для того чтобы иметь возможность записывать в слот новое значение или считывать текущее, нужно разрешить формирование соответствующих функций доступа через фацет create-accessor. Теперь сформируем экземпляр класса pistol с помощью следующего выражения:
(definstances pistols (РРК of pistol (safety on) (slide forward) (hammer down) (chamber 0) (magazine out) (rounds 6)
Этот экземпляр, РРК, правильно уложен – обойма вынута из рукоятки, пистолет установлен на предохранитель, затвор в переднем положении, курок опущен, а патронник пуст. В обойме имеется 6 патронов.
Теперь, имея в программе определение класса и сформировав экземпляр класса, разработаем правила и обработчики сообщений, с помощью которых можно описать отдельные операции обращения с пистолетом и стрельбы из него. Для этого сначала разработаем шаблон задачи. Желательно отслеживать две вещи:
- есть ли патрон в патроннике;
- произведен ли выстрел.
Для этого можно использовать следующий шаблон:
(deftemplate range-test (field check (type SYMBOL) (default no)) (field fired (type SYMBOL) (default no)))
Первое правило будет устанавливать в рабочую память программы задачу range-test.
(defrule start (initial-fact) › (assert (range-test)))
При активизации этого правила в рабочую память будет добавлено:
(range-test (check no) (fired no))