(defrule rule
(Customer (address ?address))
(PO (customer ?customer))
(test (= 0 (str-compare ((?customer getAddress) getStreet) (?
address getStreet))))
=>
(bind ?name (?customer getName))
(bind ?addr (?address getStreet))
(printout t ?addr ": customer: " ?name crlf)
)
Are there better, more elegant ways to accomplish the same?
Beauty is in the eye of the beholder, of course, but I'll offer one
alternative that might work and then a little commentary.
I tried:
?po <- (PO (customer ?customer))
?customer <- (Customer (address ?address))
(test (= (((?po getCustomer) getAddress) getStreet) ((?customer
getAddress) getStreet)))
But ?po and ?customer are facts (Jess.Fact) that have no
getCustomer and getAddress methods.
(defrule match-street-in-purchase-to-other-customers-for-some-reason
(PO (customer ?poCustomer))
(Customer (OBJECT ?poCustomer) (address ?poAddress))
(Address (OBJECT ?poAddress) (street ?street))
(Customer (OBJECT ?customer&~?poCustomer) (address ?
customerAddress)) ;This assumes we aren't matching the PO customer
(Address (OBJECT ?customerAddress) (street ?street)
=>
;; do something here with something in purchase order unshown
property (other than customer)?
)
It would also be possible to write methods on the classes that assist
in this form of matching, to reduce the direct navigation through the
object relationships. Something like a streetEq method, or more
directly a getCustomerStreet() method on the PO class to avoid
navigating in the pattern matches across the Customer.
There cam be real tension between object-oriented programming and
rule-based programming. Encapsulation of objects and avoiding
breaking Demeter's law can take a lot of the classic OPS5 rule look
out of rule-programming. Adding properties (and accessors) to all
the slots one might navigate through can add a burden to adding
objects to the engine as the properties are shadowed, particularly if
the properties are not easily computed/virtual.
- Mike