




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第一章. Drools 4.0 發(fā)布版標(biāo)注的新內(nèi)容Drools4.0是從之前的Drools3.0.x系列以來的一次主要更新。在語(yǔ)言表達(dá)式,引擎性能和工具實(shí)用性方面都有一整套的新特性開發(fā)完成。下面列出一些最引人注意的更新列表。. 語(yǔ)言表達(dá)式增強(qiáng)· 新的條件元素: from, collect, accumulate 和forall· 新的字段約束操作: not matches, not contains, in, not in, memberOf, not memberOf· 新的自索引字段: this· 對(duì)條件元素嵌套的完全支持,對(duì)一階
2、邏輯的完全支持· 支持使用&& 和|連接多個(gè)約束條件· 語(yǔ)法分析器的增強(qiáng)以去除之前的一些語(yǔ)言約束,如字符轉(zhuǎn)碼和關(guān)鍵字沖突· 支持插件式語(yǔ)言,以及對(duì)MVEL腳本語(yǔ)言的完全支持· 完全重寫的DSL引擎,允許完全的本地化· Fact屬性對(duì)于返回值約束和內(nèi)嵌求值的自動(dòng)變換· 支持嵌套訪問,屬性導(dǎo)航和簡(jiǎn)化的集合、數(shù)組以及映射的語(yǔ)法· 對(duì)XML規(guī)則的增強(qiáng)支持. 核心引擎增強(qiáng)· 對(duì)于元數(shù)據(jù)類型的本地支持,避免經(jīng)常性的自動(dòng)封包操作· 支持透明的可選的影子Fact· 對(duì)于復(fù)雜規(guī)則的Ret
3、e網(wǎng)絡(luò)性能增強(qiáng)· 支持規(guī)則流· 支持有狀態(tài)與無(wú)狀態(tài)的Working Memory(規(guī)則引擎Session)· 支持異步Working Memory操作· 規(guī)則代理(Agent)提供熱部署機(jī)制和BRMS集成· 對(duì)于規(guī)則沖突解決方案的動(dòng)態(tài)salience值· 支持參數(shù)化查詢· 支持暫停命令· 支持順序執(zhí)行模式· 支持插件式的全局變量轉(zhuǎn)換器. IDE 增強(qiáng)· 支持調(diào)試中的規(guī)則斷點(diǎn)· 對(duì)于規(guī)則流的所見即所得功能· 對(duì)于規(guī)則編制的新的向?qū)Ь庉嬈?#183; 支持所有新的引擎特
4、性. 業(yè)務(wù)規(guī)則管理系統(tǒng) - BRMS· 新的BRMS工具· 具有Web2.0 Ajax特性的用戶友好的Web界面· Package配置· 通過向?qū)Ь庉嬈髋c文本編輯器,規(guī)則的作者更容易修改規(guī)則· Package編譯和部署· 通過使用Rule Agent簡(jiǎn)化部署· 通過分類組織規(guī)則,簡(jiǎn)化規(guī)則的查找· 可版本化,你可以很容易的使用之前保存的版本替換現(xiàn)在的一套規(guī)則· 與JCR兼容的規(guī)則倉(cāng)庫(kù). 其它增強(qiáng)· 減少了依賴類庫(kù)和更少的內(nèi)存占用1.2. 之前說到,Drools4.0是自Drools3.0
5、.x系列以來的重要關(guān)鍵更新。但不幸的是為了達(dá)到這次發(fā)布的目標(biāo),帶來了一些向后兼容性的問題,如郵件列表和博客中所提到的。. API 變更只有很少的API變更是對(duì)于常規(guī)用戶可見并需要調(diào)整的。.1. Working Memory 創(chuàng)建Drools3.0.x中只有一種Working Memory類型,它的是以有狀態(tài)Working Memory的方式工作的。Drool4.0.x提供兩個(gè)獨(dú)立的有狀態(tài)與無(wú)狀態(tài)working memory,現(xiàn)在被稱為Rule Session。在Drools3.0.x中建立Working Memory的代碼是:Example 1.1. D
6、rools 3.0.x: Working Memory 創(chuàng)建WorkingMemory wm = rulebase.newWorkingMemory();在中必須變成:Example 1.2. Drools 4.0.x: 有狀態(tài)Rule Session創(chuàng)建StatefulSession wm = rulebase.newStatefulSession();StatefulSessionWorkingMemory對(duì)象的行為相同(它甚至繼承了WorkingMemory接口),因此除了創(chuàng)建代碼以外這個(gè)調(diào)整不會(huì)帶來其它問題。.2. Working Memory 操作支持可
7、插入的語(yǔ)言,并且已經(jīng)內(nèi)建了對(duì)Java和MVEL腳本語(yǔ)言的支持。為了避免關(guān)鍵字沖突,working memory的一些操作被重新命名如下:Table 1.1. Working Memory Actions equivalent API methodsWorkingMemory.assertObject()WorkingMemory.insert()WorkingMemory.assertLogicalObject()WorkingMemory.insertLogical()WorkingMemory.modifyObject()WorkingMemory.update().&
8、#160;規(guī)則語(yǔ)言的變更DRL規(guī)則語(yǔ)言也有如下一些變更是不支持向后兼容性的。.1. Working Memory ActionsWorking Memory 操作在規(guī)則推論中的變化和在方法API上的變化相似,下表描述了這些改變:Table 1.2. Working Memory Actions equivalent DRL commandsassert()insert()assertLogical()insertLogical()modify()update().2. 元數(shù)據(jù)類型支持與解包(unboxing)沒有對(duì)元數(shù)據(jù)類型的本地支持,因此它會(huì)自動(dòng)封包所
9、有的元數(shù)據(jù)類型到各自的封裝類中。這樣的化,任何封包的變量綁定需要一個(gè)手工的解包操作。已經(jīng)對(duì)元數(shù)據(jù)類型有完全的支持,不再需要封裝任何值。因此所有之前的解包操作必須從DRL中刪除。 手工解包rule "Primitive int manual unbox"when $c : Cheese( $price : price )then $c.setPrice( $Value() * 2 )end上面的規(guī)則在中將是:Example 1.4. Drools 4.0.x 元數(shù)據(jù)支持rule "Primitive support"w
10、hen $c : Cheese( $price : price )then $c.setPrice( $price * 2 )end. Drools 更新工具Drools更新工具是一個(gè)幫助你將DRL從升級(jí)到4的一個(gè)簡(jiǎn)單的程序。在這一點(diǎn)上它主要是更新working memory從3.0.x 到的操作調(diào)用,但是期待它在未來的幾個(gè)星期里可以覆蓋更多的情況。要注意的是,這個(gè)工具并不是簡(jiǎn)單的進(jìn)行字符替換,實(shí)際上它分析規(guī)則文件并確保不會(huì)做出預(yù)料之外的任何事情。因此它對(duì)于大量規(guī)則的升級(jí)來說是一個(gè)安全的工具。Drools更新工具可以在下面的源碼庫(kù)鏈接中作為一個(gè)maven項(xiàng)目獲取maven clean
11、 install 操作。在解決了所有依賴類庫(kù)的class路徑后,你可以使用下面的命令運(yùn)行這個(gè)工具:java -cp $CLASSPATH org.drools.tools.update.UpdateTool -f <filemask> -d <basedir> -s <sufix>這個(gè)程序的參數(shù)非常容易理解:· -h,-help, 顯示一個(gè)非常簡(jiǎn)單的幫助· -d 你的源碼根路徑· -f 將要被更新的文件的查找模式。這個(gè)格式與ANT中使用的相同,*=單個(gè)文件,目錄*=任何子目錄級(jí)別;例如 src/main/resources/*/
12、*.drl = 匹配所有在/src/main/resources下的子目錄中的DRL文件· -s,-suffix 被增加到所有更新文件上的后綴第2章. 規(guī)則引擎2.1. 什么是規(guī)則引擎?. 背景介紹A.I.(Artificial Intelligence)是一個(gè)關(guān)注于“使計(jì)算機(jī)像人類一樣思考“的廣泛的研究領(lǐng)域,包括Neural Networks(神經(jīng)網(wǎng)絡(luò)), Genetic Algorithms(遺傳算法), Decision Trees(決策樹), Frame Systems(框架系統(tǒng)) and Expert Systems(專家系統(tǒng))。Knowled
13、ge representation(知識(shí)呈現(xiàn))是A.I.的一部分,關(guān)注于如何呈現(xiàn)和操縱知識(shí)。專家系統(tǒng)使用知識(shí)表示把知識(shí)編碼簡(jiǎn)化成一個(gè)可用于推理的知識(shí)庫(kù)比如,我們可以用知識(shí)庫(kù)處理數(shù)據(jù)以推出結(jié)論。專家系統(tǒng)又叫基于知識(shí)的系統(tǒng)、基于知識(shí)的專家系統(tǒng),并被認(rèn)為是A.I.的一個(gè)應(yīng)用。開發(fā)一個(gè)專家?guī)煜到y(tǒng)的過程被稱為知識(shí)工程。EMYCIN是最早的專家系統(tǒng)Shell(外殼)之一,它從醫(yī)學(xué)診斷專家系統(tǒng)MYCIN發(fā)展而來。早期的專家系統(tǒng)有自己的logic hard coded "shells"(邏輯硬件編碼外殼),把邏輯與系統(tǒng)相分離,為用戶輸入提供一個(gè)簡(jiǎn)單的使用環(huán)境。Drools是一個(gè)使用基于規(guī)則
14、的方法實(shí)現(xiàn)的專家系統(tǒng)的規(guī)則引擎,更準(zhǔn)確的說屬于產(chǎn)生式規(guī)則系統(tǒng)。術(shù)語(yǔ)“產(chǎn)生式規(guī)則”從形式語(yǔ)法中產(chǎn)生,形式語(yǔ)法使用一種抽象結(jié)構(gòu)來準(zhǔn)確描述形式語(yǔ)言 (wikipedia)。The term "Production Rule" originates from formal grammar - where it is described as "an abstract structure that describes a formal language precisely, i.e., a set of rules that mathematically delineate
15、s a (usually infinite) set of finite-length strings over a (usually finite) alphabet" (wikipedia).業(yè)務(wù)規(guī)則管理系統(tǒng)在普通的規(guī)則引擎基礎(chǔ)上通過提供集中的業(yè)務(wù)用戶,規(guī)則建立系統(tǒng),管理,發(fā)布,協(xié)作,分析和終端用戶工具等來達(dá)到更高的附加價(jià)值;使得企業(yè)能夠以更順利的方式引入規(guī)則引擎規(guī)則引擎這個(gè)術(shù)語(yǔ)是非常不明確的,因?yàn)槿魏我匀我庑问绞褂媚軌驊?yīng)用于數(shù)據(jù)生成結(jié)果的規(guī)則的系統(tǒng)都可以稱為規(guī)則引擎。包括像表單驗(yàn)證和動(dòng)態(tài)表達(dá)式引擎這樣的簡(jiǎn)單系統(tǒng)都可以稱之為規(guī)則引擎。作者M(jìn)alcolm Chisholm 的著作H
16、ow to Build a Business Rules Engine (2004)就例證了這種不明確性。該書實(shí)際是講述如何為管理校驗(yàn)規(guī)則而建立和維護(hù)一個(gè)數(shù)據(jù)庫(kù)計(jì)劃。該書中接著展示了如何根據(jù)這些校驗(yàn)規(guī)則產(chǎn)生VB代碼來校驗(yàn)輸入在某些情況下這是很有用的,作者十分驚訝于這種不明確性,在沒有覺察到各種規(guī)則引擎間細(xì)微不同之處時(shí),他希望能發(fā)現(xiàn)其中的奧秘以幫助增強(qiáng)Drools引擎。JBoss jBPM(業(yè)務(wù)流程管理工具)在它的判斷節(jié)點(diǎn)上使用表達(dá)式和代理引用來控制工作流中的事務(wù)。通過在每個(gè)節(jié)點(diǎn)上求值以決定分支的流向這同樣是一個(gè)規(guī)則引擎。產(chǎn)生式規(guī)則系統(tǒng)既是一種規(guī)則引擎,又是一個(gè)專家系統(tǒng),而之前提到的校驗(yàn)器和表達(dá)
17、式求值規(guī)則引擎不是專家系統(tǒng)產(chǎn)生式規(guī)則系統(tǒng)完全關(guān)注于精確表達(dá)propositional(命題)和first order logic(一階邏輯)的知識(shí)表示,不存在含糊不清的定義。產(chǎn)生式規(guī)則系統(tǒng)的核心是一個(gè)能夠處理大量規(guī)則和事實(shí)的推理引擎。推理引擎將事實(shí)、數(shù)據(jù)與產(chǎn)生式規(guī)則(也可以叫做產(chǎn)生式,或干脆叫規(guī)則)進(jìn)行匹配,以推出結(jié)論。產(chǎn)生式規(guī)則是一個(gè)用一階邏輯進(jìn)行知識(shí)呈現(xiàn)的二元結(jié)構(gòu)。when <conditions>then <actions>將新的或已存在的事實(shí)與產(chǎn)生式規(guī)則進(jìn)行匹配的過程被稱為模式匹配,這個(gè)過程由推理機(jī)完成。推理機(jī)使用的用于模式匹配的算法有很多,包括:·
18、Linear 線性的· Rete 網(wǎng)狀· Treat · Leaps 葉狀Drool實(shí)現(xiàn)了Rete和Leaps算法;Leaps是試驗(yàn)性質(zhì)的,因?yàn)樗莻€(gè)十分新的算法。Drools中的Rete算法被稱為ReteOO,表示Drools為面向?qū)ο笙到y(tǒng)(Object Oriented systems)增強(qiáng)并優(yōu)化了Rete算法。其它基于Rete算法的引擎也有他們對(duì)Rete算法進(jìn)行獨(dú)有增強(qiáng)后的市場(chǎng)術(shù)語(yǔ),比如RetePlus,ReteIII。要知道象ReteIII這樣的名字純粹是市場(chǎng)性的,不像原始版本的Rete算法,它們沒有公布實(shí)現(xiàn)細(xì)節(jié),這一點(diǎn)很重要;因此,問類似于“Drools
19、是用ReteIII實(shí)現(xiàn)的嗎?”的問題是沒有任何意義的。最尋常的對(duì)Rete算法的增強(qiáng)在下面這篇文章中有論述"Production Matching for Large Learning Systems (Rete/UL)" (1995) by Robert B. Doorenbos。規(guī)則保存在Production Memory(規(guī)則庫(kù))中,推理機(jī)要匹配的facts(事實(shí))保存在Working Memory(工作內(nèi)存)中。事實(shí)被插入到工作內(nèi)存中后,可能被修改或刪除。一個(gè)有大量規(guī)則和事實(shí)的系統(tǒng)可能會(huì)很多規(guī)則被滿足,這些規(guī)則被稱為具有沖突性。Agenda通過(沖突決策策略)管理這些
20、沖突規(guī)則的執(zhí)行順序。Figure 2.1. 基礎(chǔ)Rete網(wǎng)絡(luò)產(chǎn)生式規(guī)則系統(tǒng)的推理機(jī)是有狀態(tài)的并且能夠維持其中狀態(tài)值的準(zhǔn)確性,稱為Truth Maintence(真值維護(hù))。規(guī)則引擎中的動(dòng)作僅當(dāng)其依賴的約束為真值情況下執(zhí)行,如果約束不再有效,則推論動(dòng)作不會(huì)執(zhí)行。"Honest Politician"(Drools提供的一個(gè)示例)就是這種真值維護(hù)的示范,在示例中規(guī)定,只要在存在誠(chéng)實(shí)的政治家時(shí),一個(gè)政體才有希望。when an honest Politician existsthen logically assert Hopewhen Hope existst
21、hen print "Hurrah! Democracy Lives" when Hope does not existthen print "Democracy is Doomed" 產(chǎn)生式規(guī)則系統(tǒng)有兩種執(zhí)行方法正向推理和逆向推理,兩種方法都使用的系統(tǒng)稱為混合型產(chǎn)生式規(guī)則系統(tǒng)。理解這兩種操作方法是理解產(chǎn)生式規(guī)則系統(tǒng)之所以不同和怎樣從中選擇最合適的系統(tǒng)的關(guān)鍵。正向推理是數(shù)據(jù)驅(qū)動(dòng)的,facts事實(shí)被傳遞到工作空間中,在那里有一個(gè)或多個(gè)規(guī)則與這些事實(shí)匹配,并由Agenda安排執(zhí)行我們從一個(gè)事實(shí)開始,傳遞事實(shí),最后得到一個(gè)結(jié)論。Drools是基于正向推理的規(guī)則
22、引擎。Figure 2.2. 正向推理逆向推理是由目標(biāo)驅(qū)動(dòng)的,這意味著我們從一個(gè)引擎需要滿足的結(jié)論開始進(jìn)行推理。在這個(gè)結(jié)論不能滿足時(shí),將搜索一些能夠滿足的結(jié)論來推理,稱為子目標(biāo),這些子目標(biāo)將幫助完成當(dāng)前目標(biāo)的某些未知部分引擎持續(xù)這個(gè)過程,直到最初的結(jié)論被證明或沒有可證明的子目標(biāo)。Prolog是逆向驅(qū)動(dòng)型的引擎。Drools將在下一個(gè)主要版本中加入對(duì)逆向推理的支持。Figure 2.3. 逆向推理2.2. 為何使用規(guī)則引擎?人們常常會(huì)問到:1. 何時(shí)應(yīng)當(dāng)使用規(guī)則引擎?2. 規(guī)則引擎與"if.then" 這樣的硬編碼
23、比起來有什么優(yōu)點(diǎn)?3. 為何應(yīng)當(dāng)使用規(guī)則引擎取代腳本框架?我們嘗試通過以下說明來解答這些問題. 規(guī)則引擎的優(yōu)點(diǎn)· 聲明式編程規(guī)則引擎允許你描述做什么而不是如何去做。這里的主要優(yōu)點(diǎn)是使用規(guī)則更加容易對(duì)復(fù)雜的問題進(jìn)行表述,并得到驗(yàn)證。 (規(guī)則比編碼更容易閱讀). 規(guī)則系統(tǒng)能夠解決非常非常困難的問題,并提供了方案怎樣達(dá)到和在解決問題的方向上所作的每一個(gè)決定的原因(這對(duì)于類似神經(jīng)網(wǎng)絡(luò)這樣的AI系統(tǒng)來說不容易達(dá)到)· 邏輯與數(shù)據(jù)分離數(shù)據(jù)保存在系統(tǒng)對(duì)象中,邏輯保存在規(guī)則中。這根本性的打破了面向?qū)ο笙到y(tǒng)中將數(shù)據(jù)和邏輯耦合起來的局面,這點(diǎn)是有利的也是不利的,在于你的觀察角度。這樣
24、做的結(jié)果是,將來邏輯發(fā)生改變時(shí)更容易被維護(hù),因?yàn)檫壿嫳4嬖谝?guī)則中。這點(diǎn)在邏輯是跨領(lǐng)域或多領(lǐng)域中使用時(shí)尤其有用。通過將邏輯集中在一個(gè)或數(shù)個(gè)清晰的規(guī)則文件中,取代了之前分散在代碼中的局面。· 速度及可測(cè)量性Rete算法、Leaps算法,以及由此衍生出來的Drools的Rete、Leaps算法,提供了對(duì)系統(tǒng)數(shù)據(jù)對(duì)象非常有效率的匹配。這些都是高效率尤其當(dāng)你的數(shù)據(jù)是不完全的改變(規(guī)則引擎能夠記得之前的匹配)。這些算法經(jīng)過了大量實(shí)際考驗(yàn)的證明。· 知識(shí)集中化通過使用規(guī)則,將建立一個(gè)可執(zhí)行的規(guī)則庫(kù)。這意味著規(guī)則庫(kù)代表著現(xiàn)實(shí)中的業(yè)務(wù)策略的唯一對(duì)應(yīng),理想情況下可讀性高的規(guī)則還可以被當(dāng)作文檔使
25、用。· 工具集成例如Eclipse(將來可能在基于Web的界面上)這樣的工具為規(guī)則的修改與管理、即時(shí)獲得反饋、內(nèi)容驗(yàn)證與修補(bǔ)提供了辦法。審查與調(diào)試工具同樣也可用了。· 解釋機(jī)制通過將規(guī)則引擎的決斷與決斷的原因一起記錄下來,規(guī)則系統(tǒng)提供了很好的“解釋機(jī)制”。· 易懂的規(guī)則通過建立對(duì)象模型以及DSL(域定義語(yǔ)言),你可以用接近自然語(yǔ)言的方式來編寫規(guī)則。這讓非技術(shù)人員與領(lǐng)域?qū)<铱梢杂盟麄冏约旱倪壿媮砝斫庖?guī)則(因?yàn)槌绦虻拿詫m已經(jīng)被隱藏起來了) 。. 何時(shí)應(yīng)當(dāng)使用規(guī)則引擎?對(duì)這個(gè)問題最簡(jiǎn)短的回答就是“當(dāng)沒有令人滿意的傳統(tǒng)的程序設(shè)計(jì)方法能夠解決這個(gè)問題時(shí)”。下面上對(duì)所謂沒有傳
26、統(tǒng)解決方法的一個(gè)描述: · 對(duì)于傳統(tǒng)代碼來說,問題需要的精確度太高。這種問題可能并不復(fù)雜,但是你找不到一種穩(wěn)定的方法去建立它。· 問題超越了任何有明顯運(yùn)算法則的方案。 它是一個(gè)難以解決的復(fù)雜問題,沒有明顯的傳統(tǒng)解決方案或者問題沒有一個(gè)準(zhǔn)確的定論。· 業(yè)務(wù)邏輯經(jīng)常發(fā)生改變邏輯本身是簡(jiǎn)單的(但不是指過于簡(jiǎn)單),但是規(guī)則經(jīng)常發(fā)生變化。在許多軟件組織中正式版本的間隔是較長(zhǎng)并且較少的,規(guī)則可以在適當(dāng)?shù)陌踩疤嵯聨椭峁┮欢ǖ拿艚菪浴?#183; 領(lǐng)域?qū)<遥ɑ蛘邩I(yè)務(wù)分析師)是非技術(shù)人員領(lǐng)域?qū)<彝ǔ?duì)業(yè)務(wù)規(guī)則和流程具有很好的認(rèn)知。他們通常是不了解軟件技術(shù)的人員,但是具有很好的邏
27、輯性。規(guī)則能夠讓他們用自己的術(shù)語(yǔ)來描述業(yè)務(wù)邏輯。當(dāng)然他們?nèi)匀恍枰獓?yán)密的思考和良好的邏輯思維能力(許多在非軟件技術(shù)型崗位上的人沒有進(jìn)行過形式邏輯的訓(xùn)練,因此在和他們工作時(shí)要特別小心,在將業(yè)務(wù)知識(shí)編撰成規(guī)則時(shí),要特別注意業(yè)務(wù)規(guī)則和流程應(yīng)當(dāng)是當(dāng)前能夠理解的)。如果規(guī)則對(duì)于你的項(xiàng)目組來說是一種新的技術(shù),那在使用前必須將學(xué)習(xí)與管理的費(fèi)用成本考慮進(jìn)去。規(guī)則不是一種無(wú)意義的技術(shù),這篇文檔盡量讓其易于理解。在一個(gè)面向?qū)ο蟮膽?yīng)用中,規(guī)則引擎通常被用在包含業(yè)務(wù)邏輯的關(guān)鍵部分(具體與應(yīng)用相關(guān)),特別是在十分繁雜凌亂的部分。這是對(duì)面向?qū)ο笾袑⑺羞壿嫹庋b在對(duì)象中的一個(gè)倒置。但這并不是說應(yīng)該拋棄對(duì)象模型,相反的來說在任
28、何一個(gè)現(xiàn)實(shí)應(yīng)用中業(yè)務(wù)邏輯僅僅是應(yīng)用的一部分。如果你曾注意到在你的代碼中有很多”if”else”switch”和其它凌亂的邏輯,你總是要回過頭去修改它們(可能是由于提供給你的邏輯是錯(cuò)誤的,或是你的理解變化了),那么可以考慮使用規(guī)則。如果你所面對(duì)的問題沒有算法或者模式合適解決,考慮使用規(guī)則。規(guī)則可以被嵌入你的應(yīng)用中,或者作為一個(gè)服務(wù)使用。通常規(guī)則最好被當(dāng)作一個(gè)有狀態(tài)的組件使用因此它們通常在應(yīng)用中是一個(gè)整體。無(wú)論怎樣,在一些規(guī)則被成功定義為可重用的服務(wù)的個(gè)案中,規(guī)則是無(wú)狀態(tài)的。如果考慮在組織中使用規(guī)則,那考慮產(chǎn)品中將如何使用和更新規(guī)則是很重要的(選擇很多,但是不同的組織間有不同的需要通常這超出了應(yīng)用
29、者/項(xiàng)目團(tuán)隊(duì)的控制)。. 何時(shí)不要使用規(guī)則這里引用Drools郵件發(fā)送清單中的話(Dave Hamu):“在我看來,在使用規(guī)則引擎的興奮中,人們忘記了規(guī)則引擎只是一個(gè)復(fù)雜的應(yīng)用或方法中的一部分。實(shí)際上,規(guī)則引擎不是用于規(guī)則的工作流引擎或進(jìn)程管理工具。對(duì)特定的工作要使用恰當(dāng)?shù)墓ぞ摺.?dāng)然,必要時(shí)老虎鉗可以當(dāng)作錘子用,但那并不是發(fā)明老虎鉗的本意?!币?yàn)橐?guī)則引擎是動(dòng)態(tài)的 (動(dòng)態(tài)的在這里意味著規(guī)則可以象數(shù)據(jù)一樣保存、管理和更新),它們通常被看作發(fā)布軟件系統(tǒng)的一種解決方案(大多數(shù)IT部門似乎存在的目的是防止軟件系統(tǒng)被遺棄)。如果這是你希望使用規(guī)則引擎的原因,應(yīng)當(dāng)意識(shí)到在可以寫出公開發(fā)布的規(guī)則時(shí),
30、規(guī)則引擎能夠以最佳方式工作。做為另一個(gè)方面,你也可以考慮使用數(shù)據(jù)驅(qū)動(dòng)的設(shè)計(jì)(查找表)或者腳本/流程引擎帶有能夠在數(shù)據(jù)庫(kù)中管理并能夠動(dòng)態(tài)更新的腳本。. 腳本或流程引擎希望之前的討論能夠讓你明白何時(shí)應(yīng)該使用一個(gè)規(guī)則引擎。另一方面,基于腳本的引擎也提供了"動(dòng)態(tài)重組"的能力。 另外流程引擎 (通常為工作流)如jBPM允許你使用繪圖(或編程)方式描述過程的步驟這些步驟也能夠帶有包含簡(jiǎn)單規(guī)則的策略決策點(diǎn)。過程引擎與規(guī)則通常能夠很好的在一起工作,因此這不是一個(gè)二選一的要求。對(duì)于規(guī)則引擎的一個(gè)關(guān)鍵點(diǎn)是一些規(guī)則引擎實(shí)際上就是腳本引擎。在腳本引擎下是你的程序被牢牢綁定在腳本上(如果那
31、里有規(guī)則,則必須直接調(diào)用),這導(dǎo)致未來維護(hù)更加困難,因?yàn)樗鼈冓呄蛴谠絹碓綇?fù)雜。在腳本引擎之上的好處是能夠很容易的開始實(shí)現(xiàn)規(guī)則并迅速獲得反饋(概念上會(huì)使得命令式編程更簡(jiǎn)單) 許多人在過去已經(jīng)成功實(shí)現(xiàn)了數(shù)據(jù)驅(qū)動(dòng)的系統(tǒng)(通過控制表中保存的元數(shù)據(jù)來影響應(yīng)用的行為)保持在一定控制范圍內(nèi)時(shí)這能夠很好的工作。但是當(dāng)超過了允許范圍(如只有建立者能夠改變應(yīng)用的行為)太多這將很快失控或者導(dǎo)致應(yīng)用停滯不前。. 緊密耦合與松散耦合無(wú)疑在系統(tǒng)設(shè)計(jì)中你聽說過緊密耦合與松散耦合。通常人們認(rèn)為在設(shè)計(jì)中松散耦合是更好的,因?yàn)樵黾恿讼到y(tǒng)靈活性。同樣你可以有緊密耦合與松散耦合兩種規(guī)則。緊密耦合在這里意味著一個(gè)規(guī)則的執(zhí)行
32、后將導(dǎo)致另一個(gè)規(guī)則有一個(gè)明顯的結(jié)果,換句話說就是在規(guī)則之間有清晰的邏輯推理關(guān)系。如果你的規(guī)則都是緊密耦合的,那這些規(guī)則在將來會(huì)缺乏靈活性,并且更明顯,這樣規(guī)則引擎可能是使用過度了(因?yàn)檫壿嬍且唤M清晰的規(guī)則推理能夠被直接編碼一個(gè)決策樹可能更適宜)。這并不是說緊密耦合或松散耦合本質(zhì)就不好,但是在你考慮使用規(guī)則引擎并且捕捉規(guī)則時(shí)應(yīng)當(dāng)牢記這點(diǎn)。松散耦合使得系統(tǒng)中的規(guī)則在變更,刪除和新增時(shí)不會(huì)影響其它無(wú)關(guān)的規(guī)則。 2.3. 知識(shí)表征. 一階邏輯規(guī)則是由一階邏輯或斷言邏輯編寫而成,是由命題邏輯擴(kuò)展而來。Emil Leon Post(數(shù)學(xué)家與邏輯學(xué)家 1897-1954)是第一個(gè)制定了利
33、用符號(hào)來表示邏輯的推理系統(tǒng)作為一個(gè)推論,他證明了任何邏輯系統(tǒng)(包括數(shù)學(xué))能夠被這樣的一個(gè)符號(hào)系統(tǒng)來表達(dá)。一個(gè)命題就是一項(xiàng)能夠被歸納為True或Flase的一個(gè)聲明。如果事實(shí)能夠被一個(gè)獨(dú)立的聲明證明就稱之為“封閉聲明”。在程序中這表現(xiàn)為一個(gè)不含任何變量的表達(dá)式:10 = 2 * 5包含了一個(gè)或多個(gè)變量或Fact的表達(dá)式稱為“開放聲明”,在這種表達(dá)式中,只有當(dāng)一個(gè)變量的實(shí)例被放入表達(dá)式后,才能知道該表達(dá)式是否為真值:Person.sex = "male"在SQL語(yǔ)句中,一條語(yǔ)句的執(zhí)行結(jié)果通常是將匹配的結(jié)果返回:select * from People where People.
34、sex = "male"所有由以上SQL返回回來的數(shù)據(jù)都會(huì)推論為是男性的數(shù)據(jù),下圖顯示SQL如何作為一個(gè)推理引擎從People表中返回我們需要的結(jié)果。Figure 2.4. SQL 作為一個(gè)單純的推理引擎因此在Java中,我們可以認(rèn)為一個(gè)簡(jiǎn)單命題的形式是“變量”“運(yùn)算符”“值”在這里值通常代表一個(gè)字符串命題可以看作是一個(gè)字段約束。命題之間可以使用“&&”或“|”進(jìn)行邏輯合并。如下例:person.getEyeColor().equals("blue") | person.getEyeColor().equa
35、ls("green") 這在規(guī)則引擎中也可以用“|”邏輯運(yùn)算符來表示。Person( eyeColour = "blue" ) | Person( eyeColor = "green" ) “|”邏輯運(yùn)算也可以直接作用于字段約束上(Drools實(shí)現(xiàn)該功能)Person( eyeColour = "blue"|"green" )命題邏輯并不能表達(dá)數(shù)據(jù)結(jié)構(gòu)的標(biāo)準(zhǔn)(不具有圖靈完備性),這約束了其可以定義的問題。一階邏輯或斷言邏輯通過兩種新的量詞概念以允許表達(dá)式定義結(jié)構(gòu)具體來說是全稱量詞和存在量詞,從而
36、擴(kuò)展了命題邏輯。全稱量詞允許對(duì)每一個(gè)對(duì)象檢查某些情況是否為真,通常使用“forall”這個(gè)條件元來支持(在Drools中實(shí)現(xiàn))。存在量詞檢查對(duì)象的存在性,這意味著該對(duì)象至少要出現(xiàn)一次由“not”和“exist”這兩個(gè)條件元支持。設(shè)想我們定義了兩個(gè)類Student和Module。Module代表了一個(gè)學(xué)生在每個(gè)學(xué)期里要上的所有課程,通過List集合引用。在學(xué)期末,每個(gè)課程有一個(gè)得分。如果某個(gè)學(xué)生的所有課程中有一門低于40分代表該學(xué)生本學(xué)期不合格通過存在量詞可以使用“l(fā)ess then 40” 這樣的開放命題來檢查各Module中是否有符合該條件的情況。 public class Student
37、private String name; private List modules; . public class Module private String name; private String studentName; private int score;Java具有圖靈完備性,因此你可以通過編寫代碼遍歷數(shù)據(jù)結(jié)構(gòu)來檢查存在性。下面的代碼用來返回所有學(xué)期不合格的學(xué)生列表。 List failedStudents = new ArrayList(); for ( Iterator studentIter = students.iterator(); studentIter.hasNext(
38、) Student student = ( Student ) studentIter.next(); for ( Iterator it = student.getModules.iterator(); it.hasNext(); ) Module module = ( Module ) it.next(); if ( module.getScore() < 40 ) failedStudents.add( student ) ; break; 早期的SQL實(shí)現(xiàn)不是圖靈完備的,因此不能提供對(duì)所存取的數(shù)據(jù)結(jié)構(gòu)的量化性。目前的SQL引擎通過對(duì)嵌套SQL語(yǔ)句進(jìn)行“exist”和“in”的關(guān)鍵
39、字構(gòu)造來支持存在性。以下代碼顯示如何通過SQL和規(guī)則來獲取學(xué)期不合格的學(xué)生。select * from Students s where exists ( select * from Modules m where m.student_name = and m.score < 40 )rule "Failed_Students" when exists( $student : Student() && Module( student = $student, score < 40 ) )2.4. Rete 算法RETE算法是
40、由Charles Forgy博士發(fā)明的,發(fā)表在他的博士論文中(1978-79)。這篇文章的簡(jiǎn)化版本發(fā)布在1982年()。 單詞Rete是拉丁語(yǔ)中的網(wǎng)的意思,代表網(wǎng)絡(luò)的概念。Rete算法可以被分為兩個(gè)部分:規(guī)則編輯和允許環(huán)境中的執(zhí)行。編輯算法描述了在生產(chǎn)空間(Production Memory)的規(guī)則如何產(chǎn)生一個(gè)有效的鑒別網(wǎng)絡(luò)。用通俗的話來說,有效的鑒別網(wǎng)絡(luò)是用來過濾數(shù)據(jù)的。辦法是對(duì)在網(wǎng)絡(luò)間傳遞的數(shù)據(jù)進(jìn)行過濾。在網(wǎng)絡(luò)頂部時(shí)節(jié)點(diǎn)將匹配許多數(shù)據(jù),但是到了網(wǎng)絡(luò)底部是將匹配較少的數(shù)據(jù)。在網(wǎng)絡(luò)的很底部是終端節(jié)點(diǎn)。在Frogy博士1982年的文章中,他描述了四種基本的節(jié)點(diǎn):root,1-input,2-in
41、put和terminal。Figure 2.5. Rete Nodes所有對(duì)象通過Root節(jié)點(diǎn)進(jìn)入網(wǎng)絡(luò)。從那之后立刻進(jìn)入ObjectTypeNode節(jié)點(diǎn)。ObjectTypeNode節(jié)點(diǎn)的目的是保證引起不會(huì)做超過它需要做的工作范圍。例如有兩個(gè)對(duì)象:Account和Order。如果規(guī)則引擎嘗試在每一個(gè)節(jié)點(diǎn)評(píng)估所有對(duì)象,這將花費(fèi)很多循環(huán)。為了讓工作更有效率,規(guī)則引擎應(yīng)當(dāng)只將與節(jié)點(diǎn)匹配的對(duì)象類型傳入節(jié)點(diǎn)。最初是建立一個(gè)ObjectTypeNode節(jié)點(diǎn),所有1-input和2-input節(jié)點(diǎn)都跟在后面。通過這種方法,應(yīng)用傳進(jìn)來的Account對(duì)象不會(huì)被傳送到需要Order對(duì)象的節(jié)點(diǎn)
42、上。在Drools中,當(dāng)一個(gè)對(duì)象被設(shè)置后,它將通過對(duì)象的類在HashMap中查找有效的ObjectTypesNode節(jié)點(diǎn)列表,如果這個(gè)列表不存在,它會(huì)搜索所有的ObjectTypesNode節(jié)點(diǎn),找到有效的匹配并緩存到列表中。這能夠讓Drools通過一個(gè)instanceof檢查來匹配任何對(duì)象類型。Figure 2.6. ObjectTypeNodesObjectTypdeNode節(jié)點(diǎn)能夠向AlphaNode、LeftInputAdapteNode和BetaNode節(jié)點(diǎn)傳播數(shù)據(jù)。AlphaNode節(jié)點(diǎn)用來對(duì)字符串進(jìn)行求值。雖然在1982年的論文中只提到了等式操作,但許多Ret
43、e算法的實(shí)現(xiàn)支持其它操作。例如,A=”Mr Trout”是一個(gè)字符串等式。當(dāng)規(guī)則對(duì)一個(gè)對(duì)象類型有很多字符串等式時(shí),它們會(huì)鏈接在一起。這意味著如果應(yīng)用設(shè)置了一個(gè)Account對(duì)象,它必須滿足了一個(gè)字符串等式后才能傳遞到下一個(gè)AlphaNode節(jié)點(diǎn)。在Forgy博士的論文中,他稱之為內(nèi)在條件。下面顯示了針對(duì)Cheese對(duì)象的結(jié)合AlphaNode節(jié)點(diǎn)情況:Cheese( name = "cheddar, strength = "strong" ):Figure 2.7. AlphaNodesDrools 通過在ObjectTy
44、pdeNode 節(jié)點(diǎn)向AlphaNode節(jié)點(diǎn)傳遞時(shí)使用Hash操作優(yōu)化了Rete算法。每次一個(gè)AlphaNode節(jié)點(diǎn)被加入到ObjectTypdeNode 節(jié)點(diǎn)時(shí),將在HashMap中增加一個(gè)以字符串為鍵,AlphaNode節(jié)點(diǎn)為值的鍵值對(duì)。當(dāng)一個(gè)新的對(duì)象實(shí)例進(jìn)入ObjectTypdeNode節(jié)點(diǎn)時(shí),它可以直接從HashMap中返回正確的AlphaNode節(jié)點(diǎn),避免了多余的字符串檢查。有兩種two-input節(jié)點(diǎn)JoinNode和NotNode,都是BetaNode的類型。BetaNode節(jié)點(diǎn)用于比較兩個(gè)對(duì)象和它們的字段。兩個(gè)對(duì)象可能是相同或不同的類型。我們將這兩個(gè)輸入稱為左和右。BetaNo
45、de的左輸入通常是一組對(duì)象的列表,在Drools中稱為語(yǔ)義(Tuple)。右邊的輸入是單個(gè)的對(duì)象。這兩者能夠使用“exist”進(jìn)行對(duì)比檢查。BetaNode具有記憶功能。左邊的輸入被稱為Beta Memory,會(huì)記住所有到達(dá)過的語(yǔ)義。右邊的輸入成為Alpha Memory,會(huì)記住所有到達(dá)過的對(duì)象。Drools通過在BetaNode節(jié)點(diǎn)上建立索引擴(kuò)展了Rete算法。例如,如果我們知道一個(gè)BetaNode用來對(duì)一個(gè)字符型字段進(jìn)行檢查,對(duì)每一個(gè)進(jìn)入的對(duì)象,我們能夠使用那個(gè)字符串的值進(jìn)行一個(gè)Hash查找。這意味著當(dāng)Fact從相反的一邊進(jìn)入BetaNode時(shí),不需要再對(duì)所有Fact進(jìn)行檢索以發(fā)現(xiàn)有效鏈接
46、,只要一個(gè)查找就可以返回潛在的有效候選。在任何時(shí)候,一個(gè)有效的鏈接是發(fā)現(xiàn)語(yǔ)義與對(duì)象的鏈接,它指的是一個(gè)局部匹配,并傳播到下一個(gè)節(jié)點(diǎn)。Figure 2.8. JoinNode為了讓最初的對(duì)象,在上圖中是Cheese,進(jìn)入Rete網(wǎng)絡(luò),我們使用了一個(gè)LeftInputNodeAdapter將一個(gè)對(duì)象作為輸入并傳播一個(gè)對(duì)象的語(yǔ)義。終端節(jié)點(diǎn)被用來表示一個(gè)單獨(dú)的規(guī)則已經(jīng)匹配了它的所有條件在這一點(diǎn)上,我們說這個(gè)規(guī)則實(shí)現(xiàn)完全的匹配。一個(gè)使用“or”鏈接符的規(guī)則在每一個(gè)可能的邏輯路徑上產(chǎn)生子規(guī)則,在這種情況下可以有多個(gè)終端節(jié)點(diǎn)。Drools使用了節(jié)點(diǎn)共享技術(shù)。許多規(guī)則重復(fù)著同樣的模式,節(jié)點(diǎn)
47、共享允許我們刪除這些模式的多余復(fù)制,從而避免對(duì)每一個(gè)單獨(dú)得實(shí)例進(jìn)行重復(fù)的評(píng)估。下面兩個(gè)規(guī)則在一開始共享了相同的模式,但后面部分不同: rule when Cheese( $chedddar : name = "cheddar" ) $person : Person( favouriteCheese = $cheddar ) then System.out.println( $person.getName() + " likes cheddar" ); end rule when Cheese( $chedddar : name = "chedd
48、ar" ) $person : Person( favouriteCheese != $cheddar ) then System.out.println( $person.getName() + " does not like cheddar" ); end你可以在下圖看到,在編譯的Rete網(wǎng)絡(luò)中Alpha節(jié)點(diǎn)被共享了,但是Beta節(jié)點(diǎn)沒有共享。每一個(gè)Beta節(jié)點(diǎn)有自己的終端節(jié)點(diǎn)。如果第二個(gè)模式是相同的也會(huì)被共享。Figure 2.9. Node Sharing2.5. Drools 規(guī)則引擎. 概述Drools被分為兩個(gè)
49、主要的部分:編制和運(yùn)行時(shí)編制的過程包括為規(guī)則建立DRL或XML文件,傳入一個(gè)由Antlr 3文法器定義的解析器中。下面的翻譯要參考圖1.10理解解析器對(duì)文件中規(guī)則文法的正確性進(jìn)行檢查并為descr建立一個(gè)中間結(jié)構(gòu),在AST中的descr代表規(guī)則的描述。AST然后將descr傳入Package Builder中,由其進(jìn)行打包。Package Builder同時(shí)負(fù)責(zé)包括打包中用到的所有代碼產(chǎn)生器和編譯器。Package對(duì)象是自包含并可配置的,它是一個(gè)包含規(guī)則的序列化的對(duì)象。Figure 2.10. 編制組件RuleBase是運(yùn)行時(shí)組件,包含一個(gè)或多個(gè)Package。Packag
50、e在任何時(shí)候都可以向RuleBase中添加或刪除。一個(gè)RuleBase可以同時(shí)初始化多個(gè)Working Memory,在其間維護(hù)著一個(gè)弱引用,除非重新進(jìn)行配置。Working Memory包含許多子組件,如Working Memory Event Support(事件支持), Truth Maintenance System(真值維護(hù)系統(tǒng)), Agenda 和 Agenda Event Support(事件支持)。向Working Memory中設(shè)置對(duì)象的工作可能要在建立了一個(gè)或多個(gè)激活的規(guī)則后才結(jié)束。Agenda負(fù)有規(guī)劃激活規(guī)則運(yùn)行的責(zé)任。Figure 2.11. 運(yùn)行時(shí)組件.
51、160;編制Figure 2.12. PackageBuilderDrlParser, XmlParser 和 PackageBuilder這三個(gè)類被用來進(jìn)行編制。兩個(gè)分析類用來從提供的可讀流實(shí)例中建立descr AST模型。PackageBuilder提供相應(yīng)API使得你可以不用記住這些類。"addPackageFromDrl" 和 "addPackageFromXml"是兩個(gè)常用方法都要求一個(gè)可讀流實(shí)例作參數(shù)。下面的例子說明一個(gè)如何建立一個(gè)包括XML和DRL規(guī)則文件的包,文件的位置在相對(duì)于classpath變量中定義的路徑下。注意
52、,對(duì)于增加到當(dāng)前PackageBuilder實(shí)例中的所有規(guī)則包,必須具有同樣的包名稱空間。Example 2.1. 從多個(gè)源中建立包PackageBuilder builder = new PackageBuilder();builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "package1.drl" ) ) );builder.addPackageFromXml( new InputStreamReader( getClass().getR
53、esourceAsStream( "package2.xml" ) ) );builder.addRuleFlow( new InputStreamReader( getClass().getResourceAsStream( "ruleflow.rfm" ) ) );Package pkg = builder.getPackage(); 有一個(gè)要點(diǎn),在正式使用PackageBuilder之前,要先檢查其中是否有錯(cuò)誤。當(dāng)一個(gè)被打斷的Package加入ruleBase時(shí),將會(huì)拋出一個(gè)InvalidRulePackage,錯(cuò)誤被包含在這個(gè)Package并且只
54、有一個(gè)等價(jià)于toString()的方法有效。如果你詢問PackageBuilder,可以返回更多的有效信息。Example 2.2. 使用 PackageBuilder 檢查錯(cuò)誤PackageBuilder builder = new PackageBuilder();builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "package1.drl" ) ) );PackageBuilderErrors errors = builder.getE
55、rrors();PackagBuilder使用PackageBuilderConfiguration類配置。Figure 2.13. PackageBuilderConfigurationPackageBuilderConfiguration的默認(rèn)值可以通過程序設(shè)置或通過外部特性配置在一開始就改變。在配置之前先通過ChainedProperties類在許多位置搜索文件;當(dāng)發(fā)現(xiàn)它們之后,加入其中定義的配置到主要特性列表中;這提供了一個(gè)搜索的級(jí)別優(yōu)先性。位置優(yōu)先性的順序是:系統(tǒng)特性,用戶在系統(tǒng)特性中定義的文件,用戶Home目錄,工作目錄,各種META-INF位置。除此之外,dr
56、oosl-compiler jar在它的META-INF目錄中有它自己的默認(rèn)設(shè)置。當(dāng)前PackageBulderConfiguration處理Accumulate函數(shù)的注冊(cè),語(yǔ)言的注冊(cè)以及主要的類調(diào)用器(ClassLoader)。Drools有一個(gè)可插入的語(yǔ)言系統(tǒng),它允許其它語(yǔ)言編譯和執(zhí)行表達(dá)式與代碼塊,當(dāng)前兩種支持的語(yǔ)言是Java和MVEL。每一個(gè)都有它自己的DialectConfiguration接口實(shí)現(xiàn);Javadocs文檔中提供了每一個(gè)setter/getter的細(xì)節(jié)以及用于配置它們的特性名稱。Figure 2.14. JavaDialectConfiguratio
57、nJavaDialectConfiguration允許設(shè)置用于支持它的編譯器和語(yǔ)言水平。你可以通過在可以被ChainedProperties 實(shí)例發(fā)現(xiàn)的文件中設(shè)置"piler"特性來覆蓋它,或者你可以通過下面的程序在運(yùn)行時(shí)改變。Example 2.3. 配置JavaDialectConfiguration 使用JANINO PackageBuilderConfiguration cfg = new PackageBuilderConfiguration( );JavaDialectConfiguration javaConf = (JavaDialect
58、Configuration) cfg.getDialectConfiguration( "java" );javaConf.setCompiler( JavaDialectConfiguration.JANINO ); 如果在你的classpath中沒有Eclipse JDT Core,你必須在實(shí)例化PackageBuilder之前覆蓋這個(gè)默認(rèn)的編譯器設(shè)置,你可以通過一個(gè)ChainedProperties類可以發(fā)現(xiàn)的packagebuilder特性文件或通過下面的程序方式改變它;注意我使用特性為啟動(dòng)注入值的時(shí)間。Example 2.4. 配置 JavaD
59、ialectConfiguration 使用 JANINOProperties properties = new Properties();properties.setProperty( "piler", "JANINO" );PackageBuilderConfiguration cfg = new PackageBuilderConfiguration( properties );JavaDialectConfiguration javaConf = (JavaDialectConfiguration) cfg.getDialectConfiguration( "java" );assertEquals( JavaDialectConfiguration.JANINO, javaConf.getCompiler() ); / 確認(rèn)編譯器被正確配置 當(dāng)前允許在Janino和Eclipse JDT兩個(gè)編譯器之間選擇一個(gè),以及設(shè)置不同的JDK源碼級(jí)別
溫馨提示
- 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 科技教育在課堂中的有效運(yùn)用計(jì)劃
- 社區(qū)團(tuán)結(jié)互助的活動(dòng)示范計(jì)劃
- 《大方縣宏能能源開發(fā)有限公司貴州省大方縣金沙煤田巖腳-白花塔井田煤礦(新建)礦產(chǎn)資源綠色開發(fā)利用方案(三合一)》評(píng)審意見
- 2025年美麗的大自然標(biāo)準(zhǔn)教案合集
- 規(guī)范化銷售培訓(xùn)
- 個(gè)人年終總結(jié)培訓(xùn)
- 透析患者導(dǎo)管感染護(hù)理
- Unit 5 Lesson 28 The Study of Living Things2024-2025學(xué)年九年級(jí)英語(yǔ)上冊(cè)同步教學(xué)設(shè)計(jì)(冀教版)河北專版
- 2025年安徽貨運(yùn)從業(yè)資格證考試500題題庫(kù)
- 高中數(shù)學(xué) 第一章 空間幾何體 1.2 空間幾何體的三視圖和直觀圖 1.2.3 空間幾何體的直觀圖教學(xué)實(shí)錄 新人教A版必修2
- 運(yùn)動(dòng)損傷的預(yù)防與處理預(yù)防和處理舞蹈運(yùn)動(dòng)損傷
- 物流無(wú)人機(jī)項(xiàng)目企業(yè)運(yùn)營(yíng)實(shí)施方案
- 家鄉(xiāng)二聲部合唱譜
- 某住宅樓招投標(biāo)文件
- 成語(yǔ)故事-引狼入室
- 售后工程師的數(shù)據(jù)分析能力
- 涉網(wǎng)試驗(yàn)培訓(xùn)課件
- 典當(dāng)行行業(yè)報(bào)告
- 經(jīng)典成語(yǔ)故事葉公好龍
- 綠色金融案例分析實(shí)證分析報(bào)告
- 實(shí)驗(yàn)室擴(kuò)項(xiàng)方案
評(píng)論
0/150
提交評(píng)論