Java Votary

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            48 隨筆 :: 1 文章 :: 80 評(píng)論 :: 0 Trackbacks
          <2006年3月>
          2627281234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          常用鏈接

          留言簿(7)

          隨筆分類

          隨筆檔案

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          內(nèi)容提要
                 在本文的第一部分,我將討論規(guī)則引擎如何幫助你從軟件的應(yīng)用邏輯中分離出商業(yè)規(guī)則邏輯,以實(shí)現(xiàn)商業(yè)應(yīng)用的靈活性。另外,我還將介紹JSR-94規(guī)則引擎 API,及其開(kāi)源實(shí)現(xiàn)Drools項(xiàng)目,它是這一新技術(shù)的先驅(qū)。在第二部分,我們將介紹一個(gè)規(guī)則引擎例子,并深入地研究Drools引擎及其JSR-94 擴(kuò)展的復(fù)雜性。

          為什么使用規(guī)則引擎
                 商業(yè)世界充滿了關(guān)于變化的陳詞濫調(diào),如任何事物都會(huì)改變,唯一不變的是變化等等。而在技術(shù)領(lǐng)域里,情況正好相反。我們?nèi)匀辉谠噲D解決30年前軟件業(yè)中同樣 的一堆問(wèn)題--也許比30年前還要多的問(wèn)題。在過(guò)去的十年,IT從業(yè)人員淹沒(méi)在軟件方法學(xué)的大量文獻(xiàn)中,如快速軟件開(kāi)發(fā),極限編程,敏捷軟件開(kāi)發(fā)等,它們 無(wú)一例外地強(qiáng)調(diào)靈活和變化的重要性。
                 但商業(yè)通常比開(kāi)發(fā)團(tuán)隊(duì)所依賴的軟件過(guò)程和技術(shù)改變得更加迅速。當(dāng)商業(yè)策劃人員試圖重整IT部門,以支持新的業(yè)務(wù)轉(zhuǎn)型時(shí),仍然覺(jué)得很費(fèi)勁。

          Lost in Translation
                 雖然IT團(tuán)隊(duì)反應(yīng)迅速,但他們通常帶來(lái)"電話效應(yīng)"――IT給商業(yè)計(jì)劃的執(zhí)行帶來(lái)的阻力和它帶來(lái)的利益一樣多。不幸的是,在開(kāi)發(fā)團(tuán)隊(duì)完全理解商業(yè)決策規(guī)則 并實(shí)現(xiàn)之前,規(guī)則已經(jīng)改變了。在軟件進(jìn)入市場(chǎng)前,它已經(jīng)過(guò)時(shí)了,需要進(jìn)行重構(gòu)以滿足新的業(yè)務(wù)需求。如果你是一個(gè)開(kāi)發(fā)人員,你會(huì)知道我在說(shuō)什么。再也沒(méi)有比 在需求變動(dòng)的情況下構(gòu)造軟件讓開(kāi)發(fā)人員更沮喪的事情了。作為軟件開(kāi)發(fā)人員,你必須比業(yè)務(wù)人員更了解業(yè)務(wù),有時(shí)還要了解更多。
                 試想一下你是一位商業(yè)決策者。假如公司的成功依賴于你對(duì)于市場(chǎng)趨勢(shì)敏銳的洞察力,它常常幫助你領(lǐng)先于競(jìng)爭(zhēng)者利用變化的市場(chǎng)環(huán)境獲利。每天你都會(huì)得到更多更 好的市場(chǎng)信息,但并不要緊。完成新產(chǎn)品開(kāi)發(fā)可能需要6-9個(gè)月,在此期間,對(duì)于市場(chǎng)大膽和敏銳的洞察和信息優(yōu)勢(shì)可能已經(jīng)浪費(fèi)了。而且,當(dāng)產(chǎn)品發(fā)布時(shí),有這 樣幾種可能:產(chǎn)品沒(méi)有什么吸引人的特性,預(yù)算超支,過(guò)了產(chǎn)品的最佳發(fā)布期限,或三者兼而有之。
                 情況可能還會(huì)更糟,在完成產(chǎn)品開(kāi)發(fā)時(shí),市場(chǎng)環(huán)境和規(guī)劃產(chǎn)品開(kāi)發(fā)時(shí)相比,已經(jīng)發(fā)生了根本變化。現(xiàn)在你必須要遵守新的規(guī)則,你已經(jīng)喪失了你的邊際優(yōu)勢(shì),而且設(shè) 計(jì)軟件的五人中的三人已經(jīng)離開(kāi)了公司。你必須給接手的新人重新講解復(fù)雜的業(yè)務(wù)。如果事情不順利,你可能發(fā)現(xiàn)自己要對(duì)付一個(gè)缺少文檔,并且你完全不了解的遺 留應(yīng)用。
                 你的戰(zhàn)略在哪出現(xiàn)了問(wèn)題?你在哪里應(yīng)該可以做到更好?最近的輕量級(jí)軟件過(guò)程,如極限編程,敏捷軟件開(kāi)發(fā)等都在強(qiáng)調(diào)自動(dòng)單元測(cè)試和軟件功能優(yōu)先級(jí)的重要性。 除此之外,還有其他的原則,你的開(kāi)發(fā)團(tuán)隊(duì)可能也很熟悉,這些原則可以幫助他們對(duì)需求的變動(dòng)作出迅速反應(yīng)并縮短項(xiàng)目的開(kāi)發(fā)周期。這些原則的大多數(shù),如系統(tǒng)分 解,多年前就已經(jīng)出現(xiàn),并得到了Java平臺(tái)的支持(如JMX等),還有如面向?qū)ο蠛徒巧#呀?jīng)內(nèi)建在Java語(yǔ)言中。
                 但Java仍然是一門相當(dāng)年輕的語(yǔ)言,而且Java平臺(tái)遠(yuǎn)遠(yuǎn)還沒(méi)有完備。當(dāng)前在Java社區(qū),一個(gè)引人注目的新技術(shù)是,分離商業(yè)決策者的商業(yè)決策邏輯和應(yīng) 用開(kāi)發(fā)者的技術(shù)決策,并把這些商業(yè)決策放在中心數(shù)據(jù)庫(kù),讓它們能在運(yùn)行時(shí)(即商務(wù)時(shí)間)可以動(dòng)態(tài)地管理和修改。這是一個(gè)你值得考慮的策略。
                 為什么你的開(kāi)發(fā)團(tuán)隊(duì)不得不象商業(yè)經(jīng)理人一樣,在代碼中包含復(fù)雜微妙的商業(yè)決策邏輯呢?你怎樣才能向他們解釋決策推理的微妙之處呢?你這樣做是否謹(jǐn)慎呢?可 能不是。象bottom line一樣,某些東西在解釋的過(guò)程中丟失了。為什么要冒這樣的風(fēng)險(xiǎn),讓應(yīng)用代碼或測(cè)試代碼錯(cuò)誤地表達(dá)你的商業(yè)決策邏輯呢?如果這樣做的話,你怎樣檢查它 們的正確性呢――難道你自己想學(xué)習(xí)如何編程和編寫測(cè)試代碼,或者你的客戶會(huì)為你測(cè)試軟件?你一方面要應(yīng)付市場(chǎng),一方面要應(yīng)付軟件代碼,這實(shí)在太困難了。
                 如果能將這些商業(yè)決策規(guī)則集中地放在一個(gè)地方,以一種你可以理解的格式定義,讓你可以直接管理,而不是散落在代碼的各個(gè)角落,那該有多好。如果你能把商業(yè) 決策規(guī)則獨(dú)立于你的軟件代碼,讓開(kāi)發(fā)團(tuán)隊(duì)作出技術(shù)決策,你將會(huì)獲得更多好處。你的項(xiàng)目開(kāi)發(fā)周期會(huì)更短,軟件對(duì)于變動(dòng)的需求更靈活。

          規(guī)則引擎標(biāo)準(zhǔn)Java API
                 2003年11月,Java社區(qū)通過(guò)了Java Rule Engine API規(guī)范(JSR-94)的最后草案。這個(gè)新的API讓開(kāi)發(fā)人員在運(yùn)行時(shí)訪問(wèn)和執(zhí)行規(guī)則有了統(tǒng)一的標(biāo)準(zhǔn)方式。隨著新規(guī)范產(chǎn)品實(shí)現(xiàn)的成熟和推向市場(chǎng),開(kāi)發(fā) 團(tuán)隊(duì)將可以從應(yīng)用代碼中抽取出商業(yè)決策邏輯。
                 這就需要新一代的管理工具,幫助商務(wù)經(jīng)理人可以定義和細(xì)化軟件系統(tǒng)的行為。不必通過(guò)開(kāi)發(fā)過(guò)程來(lái)修改應(yīng)用,并假定可以得到正確的結(jié)果,經(jīng)理人將可以隨時(shí)根據(jù)需要修改決策規(guī)則,并進(jìn)行測(cè)試。
                 但這將需要開(kāi)發(fā)人員在設(shè)計(jì)系統(tǒng)時(shí)作出某些改變,并可以得到合適的開(kāi)發(fā)工具。

          分離商務(wù)和技術(shù)的關(guān)注點(diǎn)
                 這是一個(gè)非常簡(jiǎn)單的例子,從經(jīng)理人的角度,說(shuō)明如何分離商務(wù)和技術(shù)的關(guān)注點(diǎn)。
                 你管理著一個(gè)反向投資基金。你公司計(jì)算機(jī)系統(tǒng)的一部分用于分析股票價(jià)格,收益和每股凈資產(chǎn),并在需要時(shí)向你提出預(yù)警。這個(gè)計(jì)算機(jī)系統(tǒng)的工作是,識(shí)別出PE比率比市場(chǎng)平均值低的股票,并標(biāo)記出來(lái)以便進(jìn)一步的檢查。
                 你的IT部門擁有一大堆數(shù)據(jù),并開(kāi)發(fā)了一系列你可以在規(guī)則中引用的簡(jiǎn)單數(shù)據(jù)對(duì)象。現(xiàn)在,為簡(jiǎn)單起見(jiàn),假設(shè)你是一名受過(guò)良好教育的,了解技術(shù)的管理人,你了解XML的基本知識(shí),可以讓你編寫和修改簡(jiǎn)單的XML規(guī)則文件。
                 你的第一個(gè)規(guī)則是,給道瓊斯所有的股票估值,并剔除P/E比率大于10的股票(這有點(diǎn)過(guò)分簡(jiǎn)化,但這里只作為一個(gè)例子)。保留下來(lái)的股票用來(lái)生產(chǎn)一系列報(bào)表。對(duì)于這個(gè)簡(jiǎn)單的例子,你的規(guī)則文件看起來(lái)如下(我們將會(huì)過(guò)頭來(lái)討論這個(gè)文件的結(jié)構(gòu)):

          <stock:overvalued>
              <stock:index> DJIA </stock:index>
              <stock:pe> over 10.0 </stock:pe>
          </stock:overvalued>

                 一個(gè)月后,你接到一家巴西分析師公司的電話,雇傭你的公司生成一系列巴西股市的報(bào)表,但他們有更嚴(yán)格的標(biāo)準(zhǔn)。而目前在巴西,P/E比率市場(chǎng)平均值是個(gè)位 數(shù),因此你用來(lái)評(píng)估被市場(chǎng)低股票的閾值需要改變。除了較低的P/E比率,你的新客戶還要求以Price-to-Book比率作為參考標(biāo)準(zhǔn)。
                 你啟動(dòng)規(guī)則編輯器,并修改規(guī)則以匹配新的評(píng)估條件。現(xiàn)在,規(guī)則引擎剔除巴西股市中P/E比率大于6.5,以及Price to Book 比率小于等于1的股票。完成規(guī)則文件修改后,看起來(lái)如下:

          <stock:overvalued>
              <stock:index> Brazil </stock:index>
              <stock:pe> over 6.5 </stock:pe>
              <stock:pb> over 1.0 </stock:pb>
          </stock:overvalued>

                 你無(wú)需為此向開(kāi)發(fā)團(tuán)隊(duì)作任何解釋。你無(wú)需等待他們開(kāi)發(fā)或測(cè)試程序。如果你的規(guī)則引擎的語(yǔ)義足夠強(qiáng)大,讓你描述工作數(shù)據(jù),你可以隨時(shí)按需修改商業(yè)規(guī)則。
                 如果限制因素是規(guī)則的定義語(yǔ)言和數(shù)據(jù)模型,你可以確信這兩者將會(huì)標(biāo)準(zhǔn)化,并出現(xiàn)先進(jìn)的編輯器和工具,以簡(jiǎn)化規(guī)則的定義,保存和維護(hù)。
                 現(xiàn)在,我希望你已經(jīng)清楚以下的原則:在這個(gè)例子中,哪只股票是否被選擇是一個(gè)商務(wù)決策,而不是技術(shù)決策。決定將哪只股票交給你的分析師是經(jīng)理人的邏輯 ――"logic of the bottom line"。經(jīng)理人作出這些決策,并可以按需定制應(yīng)用。這些規(guī)則因此變成了一種控制界面,一種新的商業(yè)系統(tǒng)用戶界面。

          使用Rule開(kāi)發(fā)
                 如果在這個(gè)應(yīng)用場(chǎng)景中,你是一個(gè)開(kāi)發(fā)人員,你的工作會(huì)稍微輕松一些。一旦你擁有了一種用于分析股票的規(guī)則語(yǔ)言,你可以取出數(shù)據(jù)對(duì)象并交給規(guī)則引擎執(zhí)行。我們將會(huì)到規(guī)則語(yǔ)言的討論,但現(xiàn)在我們繼續(xù)剛才的例子。
                 你的系統(tǒng)將一系列的stock bean輸入規(guī)則引擎。當(dāng)規(guī)則執(zhí)行后,你可以選出符合條件的股票并可以對(duì)它們作進(jìn)一步處理。也許是把它們輸入報(bào)表生成系統(tǒng)。分析師使用這些報(bào)表幫助他們分 析股市。同時(shí),老板也可能讓你使用新的技術(shù)分析工具,并用Dow理論預(yù)測(cè)股市的底部和頂部。
                 規(guī)則引擎可以讓你的系統(tǒng)變得更簡(jiǎn)單,因?yàn)槟銦o(wú)需在代碼中編寫商務(wù)邏輯,如怎樣選擇股票,選擇股票過(guò)程中奇怪的條件組合等。這些邏輯不再進(jìn)入你的代碼。你將可以專注于數(shù)據(jù)模型。
                 現(xiàn)在可以這么認(rèn)為,通過(guò)從應(yīng)用代碼中剝離出易變的商業(yè)邏輯,你的效率會(huì)更高。但凡是總有例外――簡(jiǎn)單應(yīng)用可能并不能從規(guī)則系統(tǒng)中獲益。但如果你開(kāi)發(fā)一個(gè)大型系統(tǒng),有很多易變的商業(yè)邏輯,你可以考慮在應(yīng)用中集成規(guī)則引擎。
                 除了從應(yīng)用代碼中剝離出商業(yè)決策邏輯外,規(guī)則引擎還有其他用處。有時(shí)候你需要應(yīng)用成百上千的規(guī)則進(jìn)行決策,并且有上千個(gè)對(duì)象和這些規(guī)則一起使用。很難想象 有什么先進(jìn)的人工智能引擎可以處理這種情況。遇到這種情況,你需要一個(gè)極快的決策算法或是大型機(jī)。大型機(jī)并不便宜,但你可以非常便宜的得到效率和可伸縮性 最好的算法。

          Bob McWhirter的Drools項(xiàng)目
                 現(xiàn)在,我要介紹Drools項(xiàng)目,Charles Forgy Rete算法的一個(gè)增強(qiáng)的Java語(yǔ)言實(shí)現(xiàn)。Drools是一個(gè)Bob McWhirter開(kāi)發(fā)的開(kāi)源項(xiàng)目,放在The Codehaus上。在我寫這篇文章時(shí),Drools發(fā)表了2.0-beata-14版。在CVS中,已完整地實(shí)現(xiàn)了JSR94 Rule Engine API并提供了單元測(cè)試代碼。
                 Rete算法是Charles Forgy在1979年發(fā)明的,是目前用于生產(chǎn)系統(tǒng)的效率最高的算法(除了私有的Rete II)。Rete是唯一的,效率與執(zhí)行規(guī)則數(shù)目無(wú)關(guān)的決策支持算法。For the uninitiated, that means it can scale to incorporate and execute hundreds of thousands of rules in a manner which is an order of magnitude more efficient then the next best algorithm。Rete應(yīng)用于生產(chǎn)系統(tǒng)已經(jīng)有很多年了,但在Java開(kāi)源軟件中并沒(méi)有得到廣泛應(yīng)用(討論Rete算法的文檔參見(jiàn)http://herzberg.ca.sandia.gov/jess/docs/61/rete.html。)。
                 除了應(yīng)用了Rete核心算法,開(kāi)源軟件License和100%的Java實(shí)現(xiàn)之外,Drools還提供了很多有用的特性。其中包括實(shí)現(xiàn)了JSR94 API和創(chuàng)新的規(guī)則語(yǔ)義系統(tǒng),這個(gè)語(yǔ)義系統(tǒng)可用來(lái)編寫描述規(guī)則的語(yǔ)言。目前,Drools提供了三種語(yǔ)義模塊――Python模塊,Java模塊和 Groovy模塊。本文余下部分集中討論JSR94 API,我將在第二篇文章中討論語(yǔ)義系統(tǒng)。
                 作為使用javax.rules API的開(kāi)發(fā)人員,你的目標(biāo)是構(gòu)造一個(gè)RuleExecutionSet對(duì)象,并在運(yùn)行時(shí)通過(guò)它獲得一個(gè)RuleSession對(duì)象。為了簡(jiǎn)化這個(gè)過(guò)程, 我編寫了一個(gè)規(guī)則引擎API的fa?ade,可以用來(lái)解釋代表Drools的DRL文件的InputStream,并構(gòu)造一個(gè) RuleExecutionSet對(duì)象。
                 在上面提到了Drools的三種語(yǔ)義模塊,我接下來(lái)使用它們重新編寫上面的例子X(jué)ML規(guī)則文件。這個(gè)例子中我選擇Java模塊。使用Java模塊重新編寫的規(guī)則文件如下:

          <rule-set name="StockFlagger"
                xmlns="http://drools.org/rules"
                xmlns:java="http://drools.org/semantics/java">
            <rule name="FlagAsUndervalued">
              <parameter identifier="stock">
                <java:class>org.codehaus.drools.example.Stock</java:class>
              </parameter>
              <java:condition>stock.getIndexName().equals("DJIA");</java:condition>
              <java:condition>stock.getPE() > 10 </java:condition>
              <java:consequence>
                removeObject(stock);   ( 譯注:應(yīng)該是retractObject(stock) )
              </java:consequence>
            </rule>
          </rule-set>

                 現(xiàn)在的規(guī)則文件并沒(méi)有上面的簡(jiǎn)潔明了。別擔(dān)心,我們將在下一篇文章討論語(yǔ)義模塊。現(xiàn)在,請(qǐng)注意觀察XML文件的結(jié)構(gòu)。其中一個(gè)rule-set元素包含了 一個(gè)或多個(gè)rule元素,rule元素又包含了parameter,condition和consequence元素。Condition和 consequence元素包含的內(nèi)容和Java很象。注意,在這些元素中,有些事你可以做,有些事你不能做。目前,Drools使用 BeanShell2.0b1作為它的Java解釋器。我在這里并不想詳細(xì)的討論DRL文件和Java語(yǔ)義模塊的語(yǔ)法。我們的目標(biāo)是解釋如何使用 Drools的JSR94 API。
                 在Drools項(xiàng)目CVS的drools-jsr94模塊中,單元測(cè)試代碼包含了一個(gè)ExampleRuleEngineFacade對(duì)象,它基于 Brian Topping的Dentaku項(xiàng)目。這個(gè)fa?ade對(duì)象通過(guò)javax.rules API,創(chuàng)建了供RuleExecutionSet和RuleSession使用的一系列對(duì)象。它并沒(méi)有完全包括了Drools引擎API的所有特性和細(xì) 微差別,但可以作為新手使用API的一個(gè)簡(jiǎn)單例子。
                下面的代碼片斷顯示如何使用規(guī)則引擎的facade構(gòu)造一個(gè)RuleExecutionSet對(duì)象,并通過(guò)它獲得一個(gè)RuleSession對(duì)象。
           
          import java.io.InputStream;
          import javax.rules.*;
          import org.drools.jsr94.rules.ExampleRuleEngineFacade;
          public class Example {
              private ExampleRuleEngineFacade engine;
              private StatelessRuleSession statelessSession;
              /* place the rule file in the same package as this class */
              private String bindUri = "myRuleFile.drl"
              public Example() {
                  /* get your engine facade */
                  engine = new ExampleRuleEngineFacade();
                  /* get your input stream */
                  InputStream inputStream =
                          Example.class.getResourceAsStream(bindUri);
                  /* build a RuleExecutionSet to the engine */
                  engine.addRuleExecutionSet(bindUri, inputStream);
                  /* don't forget to close your InputStream! */
                  inputStream.close();
                  /* get your runtime session */
                  this.statelessSession = engine.getStatelessRuleSession(bindUri);
              }
              ...
          }

                 在以上的例子代碼中,你需要處理InputStream的IOException例外,這里為了簡(jiǎn)單起見(jiàn)省略了。你要做的只是構(gòu)建InputStream 對(duì)象,并把它輸入ExampleRuleEngineFacade,用來(lái)創(chuàng)建一個(gè)RuleExecutionSet對(duì)象。然后,你可以得到一個(gè) StatelessRuleSession,并用它來(lái)執(zhí)行所有的規(guī)則。使用StatelessRuleSession相對(duì)簡(jiǎn)單。我們可以給上面的類添加一 個(gè)方法,用來(lái)對(duì)一個(gè)對(duì)象列表執(zhí)行規(guī)則:

          public List getUndervalued(List stocks) {
              return statelessSession.executeRules(stocks);
          }

                 該方法輸入一個(gè)stock對(duì)象列表給規(guī)則引擎,然后使用規(guī)則評(píng)估輸入的股票對(duì)象,并剔除那些不符合價(jià)值低估標(biāo)準(zhǔn)的股票。它是個(gè)簡(jiǎn)單的例子,但足以說(shuō)明問(wèn)題。
                 在ExampleRuleEngineFacade類中,代碼會(huì)稍微有些復(fù)雜。ExampleRuleEngineFacade類創(chuàng)建了一個(gè) RuleServiceProvider對(duì)象,并用它創(chuàng)建RuleAdministrator,RuleExecutionSetProvider和 RuleRuntime對(duì)象。RuleExecutionSetProvider負(fù)責(zé)解釋InputStream,并創(chuàng)建一個(gè) RuleExecutionSet對(duì)象。RuleRuntime對(duì)象用來(lái)得到一個(gè)session,RuleAdministrator用來(lái)管理所有的對(duì) 象。在往下是Drools核心API,它的核心是Rete算法實(shí)現(xiàn)。我在這里不打算詳細(xì)討論,但你可以看看 ExampleRuleEngineFacade的代碼。
                 現(xiàn)在你已經(jīng)看到了在商業(yè)和科研方面使用規(guī)則引擎的一些例子,并對(duì)Drools項(xiàng)目有了基本的了解。在下一篇文章里,我將討論DRL文件的結(jié)構(gòu)和Java語(yǔ) 義模塊,讓你可以編寫自己的DRL文件。還將向你解釋如何編寫你自己的語(yǔ)義模塊,討論salience和working memory的概念。

          資源
          · Drools Project
          · JSR-94 Specification
           
          作者
                N. Alex Rupp is a freelance software architect and developer from Minneapolis, and the current JSR94 Lead for the Drools project.
          posted on 2006-03-11 10:00 Dion 閱讀(1760) 評(píng)論(0)  編輯  收藏 所屬分類: Rule Engine
          主站蜘蛛池模板: 盐亭县| 泸西县| 卓尼县| 汉源县| 苏尼特右旗| 竹溪县| 科技| 林州市| 汉寿县| 内江市| 澄江县| 稻城县| 济源市| 延长县| 灵武市| 平武县| 饶平县| 曲阜市| 土默特左旗| 武乡县| 灵台县| 蕲春县| 南康市| 同仁县| 从化市| 金平| 潜江市| 额济纳旗| 利津县| 拜城县| 江北区| 高青县| 金阳县| 行唐县| 烟台市| 宜宾市| 丰原市| 隆林| 三门县| 淮南市| 丹江口市|