WorkingMemory
是运行时规则引擎的主要类。它保持了所有被
asserted
进
WorkingMemory
的数据的引用,直到取消(
retracted
)。
WorkingMemory
是有状态对象。它们的生命周期可长可短。如果从一个短生命周期的角度来同一个引擎进行交互,意味着你可以使用
RuleBase
对象来为每个
session
产生一个新的
WorkingMemory
,然后在结束
session
后
discard
这个
WorkingMemory
(产生一个
WorkingMemory
是一个廉价的操作)。另一种形式,就是在一个相当长的时间中(例如一个
conversation
),保持一个
WorkingMemory
,并且对于新的
facts
保持持续的更新。当你希望
dispose
一个
WorkingMemory
的时候,最好的实践就是调用
dispose()
方法,此时
RuleBase
中对它的引用将会被移除(尽管这是一个弱引用)。不管怎样最后它将会被当成垃圾收集掉。术语
WorkingMemory Actions
代表了对
WorkingMemory
的
assertions
,
retractions
和
modifications
。
4.1 Facts
Facts
是从你的应用中,被
assert
进
WorkingMemory
中的对象(
beans
)。
Facts
是规则可以访问的任意的
java
对象。规则引擎中的
facts
并不是“
clone
”
facts
,它只是持有到你的应用中数据的引用。
Facts
是你的应用数据。
String
和其他没有
getter
和
setter
的类不是有效的
Fact
。这样的类不能使用域约束(
Field Constraints
),因为使用域约束要依靠
JavaBean
标准的
getter
和
setter
来同对象交互。
4.2 Assertion
“Assertion”
是将
facts
告诉
WorkingMemory
的动作,例如
WorkingMemory.assertObject
(yourObject)
。当你
assert
一个
fact
,它将被检查是否匹配规则。这意味着所有的匹配工作将会在
assert
的过程中完成。尽管如此,当你完成
assert facts
之后,你还要调用“
fireAllRules()
”方法来执行规则。
当一个对象被
assert
后,会返回一个
FactHandle
。这个
FactHandle
是一个代表在
Working Memory
中你的
asserted Object
的令牌(
token
)。当你希望
retract
或者
modify
一个对象的时候,这个令牌让你用来同
WorkingMemory
进行交互。
Cheese stilton
=
new
Cheese(
"
stilton
"
);
FactHandle stiltonHandle
=
workingMemory.assertObject( stilton );
WorkingMeomry
有两种
assertion
模式:
Equality
和
Identity
(默认是
Identity
)。
Identity
模式下
WorkingMemory
使用一个
IdentityHashMap
来存储所有的
asserted Objects
。这个模式下,当
asserted
的
Object
是同一个实例时,它返回同一个
FactHandle
。
Equality
模式下
WorkingMemory
使用一个
HashMap
来存储所有的
asserted Objects
。这个模式下,当
asserted
的
Object
相等时,它返回同一个
FactHandle
。
(
WorkingMemory.assertObject(yourObjcet)
只是进行
assertion
的一种
regular
方法,还存在有一种称为
logical assertion
的动作)。
4.3 Retraction
基本上就是
assert
的逆操作。当你
retract
一个
fact
,
WorkingMemory
将不再跟踪那个
fact
。任何被
activated
并依赖那个
fact
的规则将被取消。注意:完全有可能存在某条规则是依赖于一个
fact
的“不存在”(
non existence
)。在这种情况下,
retract
一个
fact
将导致一条规则被激活。对一个
Fact
进行
Retraction
,必须用
assert
时返回的那个
FactHandle
做为参数。
Cheese stilton
=
new
Cheese(
"
stilton
"
);
FactHandle stiltonHandle
=
workingMemory.assertObject( stilton );
.
workingMemory.retractObject( stiltonHandle );
4.4 Modification
当一个
Fact
被修改了,会通知规则引擎进行重新处理。在规则引擎内部实际上是对旧的
Fact
进行
retract
,然后对新的
Object
再进行
assert
。要使用
modifyObject()
方法来通知
Working Memory
,被改变的
Object
并不会自己通知规则引擎。注意:
modifyObject()
方法总是要把被修改的
Object
做为第二参数,这就允许你把一个不可变对象替换为另一个新对象。
Cheese stilton
=
new
Cheese(
"
stilton
"
);
FactHandle stiltonHandle
=
workingMemory.assertObject( stilton );
.
stilton.setPrice(
100
);
workingMemory.modifyObject( stiltonHandle, stilton );
4.5 Globals
Global
是一个能够被传进
WorkingMemory
但不需要
assert
的命名对象。大多数这些对象被用来作为静态信息或服务。这些服务被用在一条规则的
RHS
,或者可能是从规则引擎返回对象的一种方法。
List list
=
new
ArrayList();
workingMemory.setGlobal(
"
list
"
, list);
setGlobal()
方法传进去的命名对象必须同
RuleBase
中所定义的具有相同的类型(就是要同你的规则文件中用
Global
关键字所定义的类型相同),否则会抛出一个
RuntimeException
。如果一条规则在你
setGlobal
之前调用了定义的
Global
,会抛出一个
NullPointerException
。
4.6 Property Change Listener
如果你的
fact
对象是
JavaBean
,你可以为它们实现一个
property change listener
,然后把它告诉规则引擎。这意味着,当一个
fact
改变时,规则引擎将会自动知道,并进行响应的动作(你不需要调用
modifyObject()
方法来通知
WorkingMemory
)。
Proxy libraries
将会帮助实现这一切。要让
Property Change Listener
生效,还要将
fact
设置为动态(
dynamic
)模式,通过将
true
做为
assertObject()
方法的第二个参数来实现:
Cheese stilton
=
new
Cheese(
"
stilton
"
);
FactHandle stiltonHandle
=
workingMemory.assertObject( stilton,
true
);
//
specifies
t
hat this is a dynamic fact
然后要在
JavaBean
中加入一个
PropertyChangeSupport
实例,和两个方法:
addPropertyChangeListener()
和
removePropertyChangeListener()
。最后要在
JavaBean
的
setter
方法中通知
PropertyChangeSupport
所发生的变化。示例代码如下:
private
final
PropertyChangeSupport changes
=
new
PropertyChangeSupport(
this
);
public
void
addPropertyChangeListener(
final
PropertyChangeListener l) {
this
.changes.addPropertyChangeListener( l );
}
public
void
removePropertyChangeListener(
final
PropertyChangeListener l) {
this
.changes.removePropertyChangeListener( l );
}
public
void
setState(
final
String newState) {
String oldState
=
this
.state;
this
.state
=
newState;
this
.changes.firePropertyChange(
"
state
"
, oldState, newState );
5. Agenda:
Figure 5.1 . Agenda
Agenda
是
RETE
的一个特点。在一个
WorkingMemory
Action
发生时,可能会有多条规则发生完全匹配。当一条规则完全匹配的时候,一个
Activation
就被创建(引用了这条规则和与其匹配的
facts
),然后放进
Agenda
中。
Agenda
通过使用冲突解决策略(
Conflict Resolution
Strategy
)来安排这些
Activations
的执行。
引擎工作在一个“
2
阶段”模式下:
1)
WorkingMemory Actions
:
assert
新的
facts
,修改存在的
facts
和
retract facts
都是
WorkingMemory Actions
。通过在应用程序中调用
fireAllRules()
方法,会使引擎转换到
Agenda Evaluatioin
阶段。
2)
Agenda Evaluation
:尝试选择一条规则进行激发(
fire
)。如果规则没有找到就退出,否则它就尝试激发这条规则,然后转换到
WorkingMemory Actions
阶段,直到
Agenda
中为空。
这个过程一直重复,直到
Agenda
是空的,此时控制权就回到应用程序中。。当
WorkingMemory
Actions
发生时,没有规则正在被激发。
下图说明了这个循环的过程:
Figure 5.2 . Two Phase Execution
5
.
1 Conflict
Resultion
当有多条
rules
在
agenda
中,就需要解决冲突。当激发一条规则时,会对
WorkingMemory
产生副作用。规则引擎需要知道规则要以什么顺序来激发(例如,激发
rule
A
可能会引起
rule B
被从
agenda
中移除。)
Drools
采取的冲突解决策略有
2
种,按照优先级排列如下:
Salience
,
LIFO
(后进先出)。最易懂的策略是“
Salience
”,即优先级,
user
可以为某个
rule
指定一个高一点的优先级(通过附给它一个比较大的数字)。高
Salience
的
rule
将会被优先激发。
5
.
2 Agenda Groups
Agenda Groups
是划分
Agenda
中
rules
(其实是“
activations
”)的一种方法。在任意一个时刻,只有一个
group
拥有“
focus
”,这意味着只有在那个
group
中的
activations
才是有效的。
Agenda Groups
是在
grouped rules
之间创建一个“流”(
flow
)的简便的方法。你可以在规则引擎中,或是用
API
来切换具有焦点的组。如果你的规则有很明确的多“阶段”(
phases
)或多“序列”(
sequences
)的处理,可以考虑用
Agenda Groups
来达到这个目的。
每次调用
setFocus()
方法的时候,那个
Agenda Group
就会被压入一个堆栈,当这个有焦点的组为空时,它就会被弹出,然后下一个组就会被执行。一个
Agenda Group
可以出现在堆栈的多个位置。默认的
Agenda Group
是“
MAIN
”,所有没有被指定
Agenda
Group
的
Activations
都被放到那个组中,这个组总是被放在堆栈的第一个组,并默认给予焦点。
5
.
3 Agenda Filters
Figure 5.3. Agenda Filter
Filter
必须实现
AgendaFilter
接口,用来允许或禁止一个
activation
能够被激发。
Drools
提供了下面几种方便的默认实现:
·
RuleNameEndWithAgendaFilter
·
RuleNameEqualsAgendaFilter
·
RuleNameStartsWithAgendaFilter
要使用一个
filter
就要在调用
fireAllRules()
方法的时候指定它。下面的例子将对所有名字以“
Test
”结尾的规则进行过滤:
workingMemory.fireAllRules(
new
RuleNameEndsWithAgendaFilter(
"
Test
"
) );
6.事件模型(
Event Model
)
Event
包里提供了规则引擎的事件机制,包括规则激发,对象被
asserted
等等。你可以使用事件机制来进行
AOP
编程。
有两种类型的
Event
Listener
:
WorkingMemoryEventListener
和
AgendaEventListener
。
Figure 6.1. WorkingMemoryEventListener
Figure 6.2 AgendaEventListener
对两个
EventListener
接口都提供了默认实现,但在方法中并没有做任何事。你可以继承这两个默认实现来完成你自己的实现-
DefaultAgendaEventListener
和
DefaultWorkingMemoryEventListener
。下面代码说明了如何扩展一个
DefaultAgendaEventListner
并把它加到
WorkingMemory
中,例子中只完成了
afterActivationFired()
方法:
workingMemory.addEventListener(
new
DefaultAgendaEventListener() {
public
void
afterActivationFired(AfterActivationFiredEvent event) {
super
.afterActivationFired( event );
System.out.println( event );
}
});
Drools
也提供了
DebugWorkingMemoryEventListener
和
DebugAgendaEventListener
两个实现类,在这两个类的方法中实现了
debug
信息的输出:
workingMemory.addEventListener(
new
DebugWorkingMemoryEventListener() );