WorkingMemory
是運(yùn)行時(shí)規(guī)則引擎的主要類。它保持了所有被
asserted
進(jìn)
WorkingMemory
的數(shù)據(jù)的引用,直到取消(
retracted
)。
WorkingMemory
是有狀態(tài)對(duì)象。它們的生命周期可長(zhǎng)可短。如果從一個(gè)短生命周期的角度來同一個(gè)引擎進(jìn)行交互,意味著你可以使用
RuleBase
對(duì)象來為每個(gè)
session
產(chǎn)生一個(gè)新的
WorkingMemory
,然后在結(jié)束
session
后
discard
這個(gè)
WorkingMemory
(產(chǎn)生一個(gè)
WorkingMemory
是一個(gè)廉價(jià)的操作)。另一種形式,就是在一個(gè)相當(dāng)長(zhǎng)的時(shí)間中(例如一個(gè)
conversation
),保持一個(gè)
WorkingMemory
,并且對(duì)于新的
facts
保持持續(xù)的更新。當(dāng)你希望
dispose
一個(gè)
WorkingMemory
的時(shí)候,最好的實(shí)踐就是調(diào)用
dispose()
方法,此時(shí)
RuleBase
中對(duì)它的引用將會(huì)被移除(盡管這是一個(gè)弱引用)。不管怎樣最后它將會(huì)被當(dāng)成垃圾收集掉。術(shù)語
WorkingMemory Actions
代表了對(duì)
WorkingMemory
的
assertions
,
retractions
和
modifications
。
4.1 Facts
Facts
是從你的應(yīng)用中,被
assert
進(jìn)
WorkingMemory
中的對(duì)象(
beans
)。
Facts
是規(guī)則可以訪問的任意的
java
對(duì)象。規(guī)則引擎中的
facts
并不是“
clone
”
facts
,它只是持有到你的應(yīng)用中數(shù)據(jù)的引用。
Facts
是你的應(yīng)用數(shù)據(jù)。
String
和其他沒有
getter
和
setter
的類不是有效的
Fact
。這樣的類不能使用域約束(
Field Constraints
),因?yàn)槭褂糜蚣s束要依靠
JavaBean
標(biāo)準(zhǔn)的
getter
和
setter
來同對(duì)象交互。
4.2 Assertion
“Assertion”
是將
facts
告訴
WorkingMemory
的動(dòng)作,例如
WorkingMemory.assertObject
(yourObject)
。當(dāng)你
assert
一個(gè)
fact
,它將被檢查是否匹配規(guī)則。這意味著所有的匹配工作將會(huì)在
assert
的過程中完成。盡管如此,當(dāng)你完成
assert facts
之后,你還要調(diào)用“
fireAllRules()
”方法來執(zhí)行規(guī)則。
當(dāng)一個(gè)對(duì)象被
assert
后,會(huì)返回一個(gè)
FactHandle
。這個(gè)
FactHandle
是一個(gè)代表在
Working Memory
中你的
asserted Object
的令牌(
token
)。當(dāng)你希望
retract
或者
modify
一個(gè)對(duì)象的時(shí)候,這個(gè)令牌讓你用來同
WorkingMemory
進(jìn)行交互。
Cheese?stilton?
=
?
new
?Cheese(
"
stilton
"
);
FactHandle?stiltonHandle?
=
?workingMemory.assertObject(?stilton?);
WorkingMeomry
有兩種
assertion
模式:
Equality
和
Identity
(默認(rèn)是
Identity
)。
Identity
模式下
WorkingMemory
使用一個(gè)
IdentityHashMap
來存儲(chǔ)所有的
asserted Objects
。這個(gè)模式下,當(dāng)
asserted
的
Object
是同一個(gè)實(shí)例時(shí),它返回同一個(gè)
FactHandle
。
Equality
模式下
WorkingMemory
使用一個(gè)
HashMap
來存儲(chǔ)所有的
asserted Objects
。這個(gè)模式下,當(dāng)
asserted
的
Object
相等時(shí),它返回同一個(gè)
FactHandle
。
(
WorkingMemory.assertObject(yourObjcet)
只是進(jìn)行
assertion
的一種
regular
方法,還存在有一種稱為
logical assertion
的動(dòng)作)。
4.3 Retraction
基本上就是
assert
的逆操作。當(dāng)你
retract
一個(gè)
fact
,
WorkingMemory
將不再跟蹤那個(gè)
fact
。任何被
activated
并依賴那個(gè)
fact
的規(guī)則將被取消。注意:完全有可能存在某條規(guī)則是依賴于一個(gè)
fact
的“不存在”(
non existence
)。在這種情況下,
retract
一個(gè)
fact
將導(dǎo)致一條規(guī)則被激活。對(duì)一個(gè)
Fact
進(jìn)行
Retraction
,必須用
assert
時(shí)返回的那個(gè)
FactHandle
做為參數(shù)。
Cheese?stilton?
=
?
new
?Cheese(
"
stilton
"
);
FactHandle?stiltonHandle?
=
?workingMemory.assertObject(?stilton?);
.
workingMemory.retractObject(?stiltonHandle?);
4.4 Modification
當(dāng)一個(gè)
Fact
被修改了,會(huì)通知規(guī)則引擎進(jìn)行重新處理。在規(guī)則引擎內(nèi)部實(shí)際上是對(duì)舊的
Fact
進(jìn)行
retract
,然后對(duì)新的
Object
再進(jìn)行
assert
。要使用
modifyObject()
方法來通知
Working Memory
,被改變的
Object
并不會(huì)自己通知規(guī)則引擎。注意:
modifyObject()
方法總是要把被修改的
Object
做為第二參數(shù),這就允許你把一個(gè)不可變對(duì)象替換為另一個(gè)新對(duì)象。
Cheese?stilton?
=
?
new
?Cheese(
"
stilton
"
);
FactHandle?stiltonHandle?
=
?workingMemory.assertObject(?stilton?);
.
stilton.setPrice(?
100
?);
workingMemory.modifyObject(?stiltonHandle,?stilton?);
4.5 Globals
Global
是一個(gè)能夠被傳進(jìn)
WorkingMemory
但不需要
assert
的命名對(duì)象。大多數(shù)這些對(duì)象被用來作為靜態(tài)信息或服務(wù)。這些服務(wù)被用在一條規(guī)則的
RHS
,或者可能是從規(guī)則引擎返回對(duì)象的一種方法。
List?list?
=
?
new
?ArrayList();
workingMemory.setGlobal(
"
list
"
,?list);
setGlobal()
方法傳進(jìn)去的命名對(duì)象必須同
RuleBase
中所定義的具有相同的類型(就是要同你的規(guī)則文件中用
Global
關(guān)鍵字所定義的類型相同),否則會(huì)拋出一個(gè)
RuntimeException
。如果一條規(guī)則在你
setGlobal
之前調(diào)用了定義的
Global
,會(huì)拋出一個(gè)
NullPointerException
。
4.6 Property Change Listener
如果你的
fact
對(duì)象是
JavaBean
,你可以為它們實(shí)現(xiàn)一個(gè)
property change listener
,然后把它告訴規(guī)則引擎。這意味著,當(dāng)一個(gè)
fact
改變時(shí),規(guī)則引擎將會(huì)自動(dòng)知道,并進(jìn)行響應(yīng)的動(dòng)作(你不需要調(diào)用
modifyObject()
方法來通知
WorkingMemory
)。
Proxy libraries
將會(huì)幫助實(shí)現(xiàn)這一切。要讓
Property Change Listener
生效,還要將
fact
設(shè)置為動(dòng)態(tài)(
dynamic
)模式,通過將
true
做為
assertObject()
方法的第二個(gè)參數(shù)來實(shí)現(xiàn):
Cheese?stilton?
=
?
new
?Cheese(
"
stilton
"
);
FactHandle?stiltonHandle?
=
?workingMemory.assertObject(?stilton,?
true
?);??
//
specifies
t
hat?this?is?a?dynamic?fact
然后要在
JavaBean
中加入一個(gè)
PropertyChangeSupport
實(shí)例,和兩個(gè)方法:
addPropertyChangeListener()
和
removePropertyChangeListener()
。最后要在
JavaBean
的
setter
方法中通知
PropertyChangeSupport
所發(fā)生的變化。示例代碼如下:
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
的一個(gè)特點(diǎn)。在一個(gè)
WorkingMemory
Action
發(fā)生時(shí),可能會(huì)有多條規(guī)則發(fā)生完全匹配。當(dāng)一條規(guī)則完全匹配的時(shí)候,一個(gè)
Activation
就被創(chuàng)建(引用了這條規(guī)則和與其匹配的
facts
),然后放進(jìn)
Agenda
中。
Agenda
通過使用沖突解決策略(
Conflict Resolution
Strategy
)來安排這些
Activations
的執(zhí)行。
引擎工作在一個(gè)“
2
階段”模式下:
1)?
WorkingMemory Actions
:
assert
新的
facts
,修改存在的
facts
和
retract facts
都是
WorkingMemory Actions
。通過在應(yīng)用程序中調(diào)用
fireAllRules()
方法,會(huì)使引擎轉(zhuǎn)換到
Agenda Evaluatioin
階段。
2)?
Agenda Evaluation
:嘗試選擇一條規(guī)則進(jìn)行激發(fā)(
fire
)。如果規(guī)則沒有找到就退出,否則它就嘗試激發(fā)這條規(guī)則,然后轉(zhuǎn)換到
WorkingMemory Actions
階段,直到
Agenda
中為空。
這個(gè)過程一直重復(fù),直到
Agenda
是空的,此時(shí)控制權(quán)就回到應(yīng)用程序中。。當(dāng)
WorkingMemory
Actions
發(fā)生時(shí),沒有規(guī)則正在被激發(fā)。
下圖說明了這個(gè)循環(huán)的過程:
Figure? 5.2 .?Two Phase Execution
5
.
1 Conflict
Resultion
當(dāng)有多條
rules
在
agenda
中,就需要解決沖突。當(dāng)激發(fā)一條規(guī)則時(shí),會(huì)對(duì)
WorkingMemory
產(chǎn)生副作用。規(guī)則引擎需要知道規(guī)則要以什么順序來激發(fā)(例如,激發(fā)
rule
A
可能會(huì)引起
rule B
被從
agenda
中移除。)
Drools
采取的沖突解決策略有
2
種,按照優(yōu)先級(jí)排列如下:
Salience
,
LIFO
(后進(jìn)先出)。最易懂的策略是“
Salience
”,即優(yōu)先級(jí),
user
可以為某個(gè)
rule
指定一個(gè)高一點(diǎn)的優(yōu)先級(jí)(通過附給它一個(gè)比較大的數(shù)字)。高
Salience
的
rule
將會(huì)被優(yōu)先激發(fā)。
5
.
2 Agenda Groups
Agenda Groups
是劃分
Agenda
中
rules
(其實(shí)是“
activations
”)的一種方法。在任意一個(gè)時(shí)刻,只有一個(gè)
group
擁有“
focus
”,這意味著只有在那個(gè)
group
中的
activations
才是有效的。
Agenda Groups
是在
grouped rules
之間創(chuàng)建一個(gè)“流”(
flow
)的簡(jiǎn)便的方法。你可以在規(guī)則引擎中,或是用
API
來切換具有焦點(diǎn)的組。如果你的規(guī)則有很明確的多“階段”(
phases
)或多“序列”(
sequences
)的處理,可以考慮用
Agenda Groups
來達(dá)到這個(gè)目的。
每次調(diào)用
setFocus()
方法的時(shí)候,那個(gè)
Agenda Group
就會(huì)被壓入一個(gè)堆棧,當(dāng)這個(gè)有焦點(diǎn)的組為空時(shí),它就會(huì)被彈出,然后下一個(gè)組就會(huì)被執(zhí)行。一個(gè)
Agenda Group
可以出現(xiàn)在堆棧的多個(gè)位置。默認(rèn)的
Agenda Group
是“
MAIN
”,所有沒有被指定
Agenda
Group
的
Activations
都被放到那個(gè)組中,這個(gè)組總是被放在堆棧的第一個(gè)組,并默認(rèn)給予焦點(diǎn)。
5
.
3? Agenda Filters
Figure 5.3.?Agenda Filter
Filter
必須實(shí)現(xiàn)
AgendaFilter
接口,用來允許或禁止一個(gè)
activation
能夠被激發(fā)。
Drools
提供了下面幾種方便的默認(rèn)實(shí)現(xiàn):
·????????
RuleNameEndWithAgendaFilter
·????????
RuleNameEqualsAgendaFilter
·????????
RuleNameStartsWithAgendaFilter
要使用一個(gè)
filter
就要在調(diào)用
fireAllRules()
方法的時(shí)候指定它。下面的例子將對(duì)所有名字以“
Test
”結(jié)尾的規(guī)則進(jìn)行過濾:
workingMemory.fireAllRules(?
new
?RuleNameEndsWithAgendaFilter(?
"
Test
"
?)?);
6.事件模型(
Event Model
)
Event
包里提供了規(guī)則引擎的事件機(jī)制,包括規(guī)則激發(fā),對(duì)象被
asserted
等等。你可以使用事件機(jī)制來進(jìn)行
AOP
編程。
有兩種類型的
Event
Listener
:
WorkingMemoryEventListener
和
AgendaEventListener
。
Figure 6.1.?WorkingMemoryEventListener
Figure 6.2? AgendaEventListener
對(duì)兩個(gè)
EventListener
接口都提供了默認(rèn)實(shí)現(xiàn),但在方法中并沒有做任何事。你可以繼承這兩個(gè)默認(rèn)實(shí)現(xiàn)來完成你自己的實(shí)現(xiàn)-
DefaultAgendaEventListener
和
DefaultWorkingMemoryEventListener
。下面代碼說明了如何擴(kuò)展一個(gè)
DefaultAgendaEventListner
并把它加到
WorkingMemory
中,例子中只完成了
afterActivationFired()
方法:
workingMemory.addEventListener(?
new
?DefaultAgendaEventListener()?{????????????????????????????
???
public
?
void
?afterActivationFired(AfterActivationFiredEvent?event)?{
???????
super
.afterActivationFired(?event?);
???????System.out.println(?event?);
???}
???
});
Drools
也提供了
DebugWorkingMemoryEventListener
和
DebugAgendaEventListener
兩個(gè)實(shí)現(xiàn)類,在這兩個(gè)類的方法中實(shí)現(xiàn)了
debug
信息的輸出:
workingMemory.addEventListener(?
new
?DebugWorkingMemoryEventListener()?);