8.2.在Jess和Java代码间传递值
本节讲述简单易用的Jess和Java代码间的输入/输出值的传递机制。
在Java的类jess.Rete中提供了下列方法:
public Value store(String name, Value val); public Value store(String name, Object val); public Value fetch(String name); public void clearStorage();
对应的在Jess中可使用:
(store <name> <value>) (fetch <name>) (clear-storage)
以上两种方法都以“name”及一个值为参数(在Java中可以是jess.Value对象或一个普通的Java对象;在Jess中可以是任何值),返回同名的任意值,或空(Java中的null;Jess中的nil)。利用这些函数可以在Jess和Java间传递无法用文本表达的数据(当然也可以传递String类型的数据)。下面在Java中建立一个对象,然后在命令行下将其作为一个参数传递给Jess。
import jess.*; public class ExFetch { public static void main(String[] unused) throws JessException { Rete r = new Rete(); r.store("DIMENSION", new java.awt.Dimension(10, 10)); r.eval("(bind ?list (list dimension (fetch DIMENSION)))"); r.eval("(printout t ?list)"); } } C:\> java ExFetch (dimension <Java-Object:java.awt.Dimension>)
注意:存储一个空值(null或nil)将导致该参数整个从哈希表(hashtable)中删除。clearStorage()及clear-storage都可以用于从哈希表中删除数据。
注意:Jess clear及Java clear()函数将调用clearStorage(),而reset及reset()则不会。因此存储的数据可以由reset()调用。
8.3.在Jess中实现Java接口
许多Java库都要求使用者对其进行回收。所谓回收是指实现了某一特殊接口;可以将其传递给库方法(livrary method),同时该回收方法在指定时间被调用。GUI的工作方式如下:回收被称为事件处理者(event-handler)。但Java线程也已该方式运行:由一个新的线程激活的可捕获的接口(Runnable)称为回收。因此在Java编程中一个接口的可实现性相当重要。
Jess支持使用implement函数创建回收。该函数使用简便:只要给定接口名称及deffunction的名称,并调用该函数就能返回一个实现该接口的对象。当任意该接口的一个方法被激活时,第一个参数是接口函数的名称,接下来是所有该接口函数所用的参数。
以实现java.util.Comparator接口为例,该接口用于对大小写敏感的字符串进行排序:
Jess> (import java.util.Comparator) Jess> (deffunction compare(?name ?s1 ?s2) (return ((?s1 toUpperCase) compareTo (?s2 toUpperCase)))) TRUE Jess> (bind ?c (implement Comparator using compare))
8.3.1.Lambda(l)表达式
调用implement时有一条不错的捷径。不用另外定deffunction,而是定义一个嵌入式的lambda工具。通过该lambda函数可以不用事先命名就定义一个deffunction,而且不用将其添加到Rete引擎中。因此上例可以用lambda表示为:
Jess> (import java.util.Comparator) Jess> (bind ?c (implement Comparator using (lambda (?name ?s1 ?s2) (return ((?s1 toUpperCase) compareTo (?s2 toUpperCase))))))
8.4.工作内存中的Java对象
可以用difinstance使Jess模式匹配到Java对象。同样也可以将Java对象带入Jess中,对此在本文档的其它部分有相关描述。这部分将描述对象在这类转换中所需的最小配置。
Jess可以调用工作内存中任何对象的equals及hashCode方法。因此这些方法的正确实现显得十分重要。Java API文档列出了equals及hashCode方法的一些重要属性,但这里还是要重申其中最重要的一点(也是最容易忽视的一点):在使用equals时,很可能也必须编写hashCode。因为对于一个类的任意一对实例来说,如果他们的equals返回true,则对于这对实例而言hashCode必须返回同样的值。(For any pair of instances of a class for which equals returns true, hashCode must return the same value for both instances.)如果不遵循该规则,Jess将出现故障,故障的起因就在于处理的元素(fact)中包含了上述违规定义的对象,这些对象存放于元素的插口(slot)中。特别是这类错误会造成没能触发应该触发的规则。
一个值对象(value object)指一种用于表示一个特殊值的类的实例。这类实例通常是不可变的,如整数型、双精度型及字符串型。对于Jess而言,值对象的hashCode()方法返回的是一个常数——例如:其哈希代码(hash code)在类正常操作中保持不变。根据该定义,任何一个不重写(override)默认hashCode()方法的类都可以实现为值对象,因为他们的哈希代码取决于收集(collection)的内容。
在Jess中,一个对象只要其在工作内存中时哈希代码保持不变就可称为值对象。这就包含了这样一种情况,在这种情况下该对象包含于任何一个元素的插口中。如果一个对象的哈希代码仅在调用modify时被改变,则仍然是一个值对象。
Jess可以对值对象作特定的假设,从而在模式匹配中极大的提高性能。因为许多类事实上是由Jess广泛定义的值类。Jess现在假设所有对象(除了collection),在默认情况下都是值对象。如果遇到不是值类的类,则必须由使用者在Jess中,使用set-nonvalue-class函数或jess.HashCodeComputer.setNonValueClass()的静态方法;否则将导致未定义(undifined有害)行为。
8.5.设置并读取Java Bean属性
上面曾提到Java对象可以显式的模式匹配于左手边(LHS)规则,但仅限于该对象是Java Bean时。一个Java Bean就是一个Java对象,该对象拥有一系列方法,这些方法都遵循一个简单的命名规则,这些规则用于Java Bean属性的命名。
·一个名为getX的方法返回T并可不带参数的调用;或者,如果T是布尔型的,则命名为isX,也不带参数。
·一个名为setX的方法返回一个空值(void)并接受单个类型为T的参数。
注意:大写也很重要。例如:如果一个方法名为isVisible,则属性名就是visilbe,其属性中的v用小写。只有名字的首字母用大写,这一点很重要。这样就可以很方便的通过Jess中的set和get方法使用set和get这些属性。