<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kapok

    垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks
    http://rosen.blogjava.net/archive/2005/09/11/12668.html

     大部分 web 以及企業級 Java 應用可被分成三部分:與用戶交互的前臺,與數據庫這樣的后臺系統交互的服務層,以及它們之間的業務邏輯。最近這段時間,通常我們會使用框架來實現前臺和后臺的需求(例如:Struts, Cocoon, Spring, Hibernate, JDO, 以及實體 Beans),但是卻沒有一種標準手段很好的組織業務邏輯。像 EJB 和 Spring 這樣的框架都以 high level 方式處理,這無助于組織我們的代碼。除非我們改變這種凌亂,否則系統將不會健壯,框架中雜亂的 if...then 語句能帶給我們可配置性、可讀性的優點,以及在其他地方復用代碼的愉悅嗎?本文將介紹如何使用 Drools 規則引擎框架來解決這些問題。
       
        下列的范例代碼展示了我們正要試圖努力避免的問題。展示了包含一些業務邏輯的 Java 典型應用。
       
    if ((user.isMemberOf(AdministratorGroup)
          && user.isMemberOf(teleworkerGroup))
         || user.isSuperUser(){
            
             // more checks for specific cases
             if((expenseRequest.code().equals("B203")
               ||(expenseRequest.code().equals("A903")
                            &&(totalExpenses<200)
                    &&(bossSignOff> totalExpenses))
               &&(deptBudget.notExceeded)) {
                   //issue payments
               } else if {
                   //check lots of other conditions
               }
    } else {
         // even more business logic
    }

        我們經常寫出類似的(甚至更復雜)業務邏輯。當這些用 Java 實現的業務邏輯成為標準方式時,將存在下列問題:
       
            業務用戶怎樣在這些難以理解的代碼基礎上添加另一個條件(比如"C987")?一旦最初開發這些程序的員工離開了,你想成為維護這些代碼的人嗎?
            我們怎樣檢查規則的正確性?對業務伙伴的技術人員來說都夠復雜的了,更不要說檢查。我們可以有系統的測試這些業務邏輯嗎?
            很用應用都有相似的業務規則--當其中的一個規則改變,我們能保證這一改變可貫穿整個系統?當新應用使用這些規則,該應用已經部分添加了新的規則,但不完全,我們要把邏輯重寫過嗎?
            我們經常需要對每個細小調整所帶來的改變進行重編譯/重部署,而不是堅實的依靠 Java 代碼,業務邏輯是否易于配置?
            可否復用已存在的用其他(腳本)語言編寫的業務規則邏輯?
           
        J2EE/EJB 以及“IoC inversion of control”框架(比如 Spring,Pico,以及 Avalon)給我們帶來的是 high level 代碼組織能力。在提供良好復用性、可配置性、以及安全性的同時,沒有一個能替代(解決)以上的“spaghetti 代碼”范例出現的問題。理想地,無論選擇何種框架,不僅僅適合 J2EE 應用,而且也可用于“normal”Java(J2SE)程序,以及大部分普遍采用的表現層以及持久層框架。這種理想框架應該允許我們這樣做:
       
            業務用戶應該可以方便的閱讀和校驗業務邏輯。
            業務規則應該可被復用,并可以通過程序進行配置。
            這種框架應該是可升級的,并在高負載情況下運行。
            Java 程序員可以像使用現有的前臺(Struts,Spring)和后臺(ORM object-relational mapping)框架一樣方便地使用這個框架。
           
        另外的問題是,有許多的 web 頁面、數據庫訪問組織方式,業務邏輯在這兩種應用中應趨于不同。而框架應該能應付這些并促進代碼復用。理想的框架將能“frameworks all the way down.”,通過這種方式使用框架,我們能在應用中大量的“out of the box”,這樣我們只為客戶記錄添加值的部分。
       
    規則引擎前來救援

        我們怎樣解決問題呢?一種方案是通過規則引擎獲取 traction。規則引擎是為組織業務邏輯應運而生的框架,它讓開發者專注于做被認為正確的事情上,而不是以 low-level 方式作出決定。
       
        通常,業務用戶舒適的表達他們知道的正確的事,而不是 if...else 格式的表達方式。你也許能從業務專家聽見這些東西:
       
        “FORM 10A 用來索取額外 200 歐元費用。(FORM 10A is used for expense claims over 200 Euro.)”
        “我們只進行數量在 10,000 以上的貿易?!?BR>    “購買大于 €10m 的要經過公司董事批準?!?BR>   
        通過專注于我們認為正確的事情上,而不是只知道怎樣用 Java 代碼表達,那么上面的敘述將比之前的代碼范例更清晰。我們仍然需要一種機制為我們知道和做決定的事實應用這些規則。這種機制就是規則引擎。
       
    Java 中的規則引擎
       
        JSR 94,如同 JBDC 允許我們與多種數據庫交互一樣,javax.rules 是一組與規則引擎交互的通用標準 API。為什么 JSR-94 沒有詳細說明實際的規則怎樣書寫,有下面大量的 Java 規則引擎可供選擇:
       
        Jess 或許是最成熟的 Java 規則引擎,有良好的工具支持(包括 Eclipse 插件)以及文檔。但是,它是商業軟件,而且用 Prolog-style 符號書寫規則,對 Java 程序員來說是很晦澀的。
        Jena 是一套開源框架,最初由惠普發起。雖然它有規則引擎以及在 Web 語義方面特別強大,但它并不與 JSR-94 兼容。
        Drools 是與 JSR-94 兼容的規則引擎,并且在 Apache-style 許可下完全開源。它不僅用熟悉的 Java 和 XML 語法表述規則,而且它還有強大的用戶、開發者社區。在本文中有范例,我們將使用 Drools,因為它有最容易使用的類似 Java 的語法以及完全開發許可。
       
    利用 Drools 開始 Java 開發

        假設有這樣的場景:在閱讀本文的數分鐘后,你老板要求你做一個股票交易應用原型。這時,業務用戶尚未被完全定義業務邏輯,你馬上會想到最好的辦法是用規則引擎實現。最終系統將可通過內部網訪問,而且還要和后臺數據庫以及消息系統通訊。在著手行動前,先下載 Drools 框架(與支持庫一起)。在你喜歡的 IDE 中創建新項目,確定所有 .jar 文件被引用進項目,如圖 1 中所示。截圖是基于 Eclipse 的,不過在其他 IDE 中創建也是相似的。

          Libraries needed to Run Drools
                       圖 1. 運行 Drools 所需要的庫
       
        如果我們的股票交易系統很混亂,將失去大量潛在客戶(商機),所以在系統的整個步驟中放入一些模擬器(simulator)是至關重要的。這種模擬器給了你決心采用該系統的信心,甚至規則改變以后所帶來的麻煩。我們將借助敏捷工具箱中的工具,以及 JUnit(http://www.junit.org/) 框架進行模擬。
       
        如下,我們寫的第一段代碼是 JUnit 測試/模擬器。即使我們無法測試每個對應用有價值的輸入組合,但有測試也比沒有測試的好。在這個范例中,所有的文件和類(包括單元測試)都放入一個文件夾/包中,但實際上,你可能會用一種適當的包、文件夾結構。范例代碼中我們用 Log4j 代替 System.out 調用。
       
    import junit.framework.TestCase;
    /*
     * JUnit test for the business rules in the
     * application.
     *
     * This also acts a 'simulator' for the business
     * rules - allowing us to specify the inputs,
     * examine the outputs and see if they match our
     * expectations before letting the code loose in 
     * the real world.
     */
    public class BusinessRuleTest extends TestCase {
      /**
      * Tests the purchase of a stock
      */
      public void testStockBuy() throws Exception{
                   
        //Create a Stock with simulated values
        StockOffer testOffer = new StockOffer();
        testOffer.setStockName("MEGACORP");
        testOffer.setStockPrice(22);
        testOffer.setStockQuantity(1000);
                   
        //Run the rules on it
        BusinessLayer.evaluateStockPurchase(testOffer);
                   
        //Is it what we expected?
        assertTrue(
          testOffer.getRecommendPurchase()!=null);
       
        assertTrue("YES".equals(
          testOffer.getRecommendPurchase()));              
       }
    }

        這是最基本的 JUnt 測試,我們知道我們的系統應該買所有低于 100 歐元的股票。很明顯,要是沒有數據持有類(StockOffer.java)和業務層類(BusinessLayer.java)它將無法編譯。這兩個類如下。
       
    /**
     * Facade for the Business Logic in our example.
     *
     * In this simple example, all our business logic
     * is contained in this class but in reality it
     * would delegate to other classes as required.
    */
    public class BusinessLayer {
      /**
       * Evaluate whether or not it is a good idea
       * to purchase this stock.
       * @param stockToBuy
       * @return true if the recommendation is to buy
       *   the stock, false if otherwise
       */
      public static void evaluateStockPurchase
        (StockOffer stockToBuy){
                    return false;
      }
    }

        StockOffer 是這樣:

    /**
     * Simple JavaBean to hold StockOffer values.
     * A 'Stock offer' is an offer (from somebody else)
     * to sell us a Stock (or Company share).
     */
    public class StockOffer {
           
      //constants
      public final static String YES="YES";
      public final static String NO="NO";
           
      //Internal Variables
      private String stockName =null;
      private int stockPrice=0;
      private int stockQuantity=0;
      private String recommendPurchase = null;
           
      /**
       * @return Returns the stockName.
       */
      public String getStockName() {
            return stockName;
      }
      /**
       * @param stockName The stockName to set.
       */
      public void setStockName(String stockName) {
            this.stockName = stockName;
      }
      /**
       * @return Returns the stockPrice.
       */
      public int getStockPrice() {
            return stockPrice;
      }
      /**
       * @param stockPrice The stockPrice to set.
       */
      public void setStockPrice(int stockPrice) {
            this.stockPrice = stockPrice;
      }
      /**
       * @return Returns the stockQuantity.
       */
      public int getStockQuantity() {
            return stockQuantity;
      }
      /**
       * @param stockQuantity to set.
       */
      public void setStockQuantity(int stockQuantity){
            this.stockQuantity = stockQuantity;
      }
      /**
       * @return Returns the recommendPurchase.
       */
      public String getRecommendPurchase() {
            return recommendPurchase;
      }
    }

        通過 IDE 的 JUnit 插件運行 BusinessRuleTest。如果你不熟悉 JUnit,可在 JUnit 網站找到更多信息。不必驚訝,如圖 2 所示第二個斷言測試失敗,這是因為還沒把業務邏輯放在適當的地方。測試結果用高亮顯示了模擬器/單元測試所出現的問題,這是很保險的。

      JUnit Test Results
                  圖 2. JUnit 測試結果
                 
    用規則編寫業務邏輯
       
        在這里,我們要寫一些業務邏輯,來表達“一旦股票價格低于 100 歐元,就馬上購買?!?要達到這個目的,需調整 BusinessLayer.java:
       
    import java.io.IOException;
    import org.drools.DroolsException;
    import org.drools.RuleBase;
    import org.drools.WorkingMemory;
    import org.drools.event.DebugWorkingMemoryEventListener;
    import org.drools.io.RuleBaseLoader;
    import org.xml.sax.SAXException;
    /**
     * Facade for the Business Logic in our example.
     *
     * In this simple example, all our business logic
     * is contained in this class but in reality it
     * would delegate to other classes as required.
     * @author default
     */
    public class BusinessLayer {
      //Name of the file containing the rules
      private static final String BUSINESS_RULE_FILE=
                                  "BusinessRules.drl";
           
      //Internal handle to rule base
      private static RuleBase businessRules = null;
      /**
       * Load the business rules if we have not
       * already done so.
       * @throws Exception - normally we try to
       *          recover from these
       */
      private static void loadRules()
                           throws Exception{
        if (businessRules==null){
          businessRules = RuleBaseLoader.loadFromUrl(
              BusinessLayer.class.getResource(
              BUSINESS_RULE_FILE ) );
        }
      }    
           
      /**
       * Evaluate whether or not to purchase stock.
       * @param stockToBuy
       * @return true if the recommendation is to buy
       * @throws Exception
       */
      public static void evaluateStockPurchase
           (StockOffer stockToBuy) throws Exception{
                   
        //Ensure that the business rules are loaded
        loadRules();
        //Some logging of what is going on
        System.out.println( "FIRE RULES" );
        System.out.println( "----------" );
           
        //Clear any state from previous runs
        WorkingMemory workingMemory
                = businessRules.newWorkingMemory();
        //Small ruleset, OK to add a debug listener
        workingMemory.addEventListener(
          new DebugWorkingMemoryEventListener());
           
        //Let the rule engine know about the facts
        workingMemory.assertObject(stockToBuy);
           
        //Let the rule engine do its stuff!!
        workingMemory.fireAllRules();
      }
    }

        這個類有些重要方法:
       
        loadRules(),從 BusinessRules.drl 文件加載規則。
        更新后的 evaluateStockPurchase(),用于評估業務規則。這個方法的注解如下:
            可以反復復用相同的 RuleSet(內存中的業務規則是無狀態的)。
            為每次評估構造新的 WorkingMemory,因為我們的知識知道這個時刻是正確的。使用 assertObject() 放置已知事實(作為 Java 對象)到內存中。
            Drools 有個事件監聽模式,允許我們“查看”事件模型中到底發生了什么。在這里我們用它打印 debug 信息。
            working memory 類中的 fireAllRules() 方法評估和更新規則(在本例中是股票出價)。
       
        再次運行該范例前,需要創建我們的 BusinessRules.drl 文件:
       
    <?xml version="1.0"?>
    <rule-set name="BusinessRulesSample"
      xmlns="
    http://drools.org/rules"
      xmlns:java="
    http://drools.org/semantics/java"
      xmlns:xs
        ="
    http://www.w3.org/2001/XMLSchema-instance"
      xs:schemaLocation
        ="
    http://drools.org/rules rules.xsd
     
    http://drools.org/semantics/java java.xsd">
      <!-- Import the Java Objects that we refer
                              to in our rules -->       
      <java:import>
        java.lang.Object
      </java:import>
      <java:import>
        java.lang.String
      </java:import>
      <java:import>
        net.firstpartners.rp.StockOffer
      </java:import>
      <!-- A Java (Utility) function we reference
        in our rules--> 
      <java:functions>
        public void printStock(
          net.firstpartners.rp.StockOffer stock)
            {
            System.out.println("Name:"
              +stock.getStockName()
              +" Price: "+stock.getStockPrice()    
              +" BUY:"
              +stock.getRecommendPurchase());
            }
      </java:functions>
    <rule-set>
      <!-- Ensure stock price is not too high-->     
      <rule name="Stock Price Low Enough">
        <!-- Params to pass to business rule -->
        <parameter identifier="stockOffer">
          <class>StockOffer</class>
        </parameter>
        <!-- Conditions or 'Left Hand Side'
            (LHS) that must be met for
             business rule to fire -->
        <!-- note markup -->
        <java:condition>
          stockOffer.getRecommendPurchase() == null
        </java:condition>
        <java:condition>
          stockOffer.getStockPrice() < 100
        </java:condition>
        <!-- What happens when the business
                          rule is activated -->
        <java:consequence>
            stockOffer.setRecommendPurchase(
                                  StockOffer.YES); 
              printStock(stockOffer);
        </java:consequence>
      </rule>
    </rule-set>

        該規則文件有些有趣部分:
       
            只有在 XML-Schema 定義 Java 對象之后,我們才能引用進規則。這些對象可以是來自于任何必須的 Java 類庫。
            接下來是 functions,它們可以與標準 Java 代碼進行混合。既然這樣,我們干脆混入些日志功能來幫助我們觀察發生了什么。
            再下來是我們的 rule set,rule set 由一到多個規則組成。
            每個規則可持有參數(StockOffer 類),并需要實現一個或多個條件,當條件符合時,將會執行相應結果。
           
        在修改和編譯完代碼后,再次運行 JUnit 測試。這次調用了業務規則,我們的邏輯進行正確地評估,并且測試通過,參看圖 3。恭喜--你已經構建了第一個基于規則的應用!

        Successful JUnit Test
        圖 3.成功的 JUnit 測試
       
    使規則更聰明

        剛剛構建好應用,你就向業務用戶示范上面的原型,他們卻忽然想起先前并沒有提出的規則。其中一個新規則是當數量是負數時(<0)不能進行股票交易?!皼]關系,”你說,接著回到辦公桌上,緊扣已有知識,快速演化你的系統。
       
        首先要更新模擬器,把以下代碼添加到 BusinessRuleTest.java:
       
      /**
       * Tests the purchase of a stock
       * makes sure the system will not accept
       * negative numbers.
       */
      public void testNegativeStockBuy()
                                    throws Exception{
                   
        //Create a Stock with our simulated values
          StockOffer testOffer = new StockOffer();
            testOffer.setStockName("MEGACORP");
            testOffer.setStockPrice(-22);
            testOffer.setStockQuantity(1000);
                   
            //Run the rules on it
            BusinessLayer
                  .evaluateStockPurchase(testOffer);
                   
            //Is it what we expected?
            assertTrue("NO".equals(
              testOffer.getRecommendPurchase()));
    }

        這個測試是為業務用戶描述的新規則建立的。正如意料之中的,如果運行 JUnit 測試,我們的新測試將失敗。所以,我們要添加新的規則到 .drl 文件:
       
    <!-- Ensure that negative prices
                                are not accepted-->     
      <rule name="Stock Price Not Negative">
        <!-- Parameters we can pass into
                              the business rule -->
        <parameter identifier="stockOffer">
          <class>StockOffer</class>
        </parameter>
        <!-- Conditions or 'Left Hand Side' (LHS)
           that must be met for rule to fire -->
        <java:condition>
          stockOffer.getStockPrice() < 0
        </java:condition>
        <!-- What happens when the business rule
                                  is activated -->
        <java:consequence>
          stockOffer.setRecommendPurchase(
                                      StockOffer.NO);      
          printStock(stockOffer);
        </java:consequence>
      </rule>

        這個規則的格式和前面的相似,除了 <java:condition>(用于測試負數)以及 <java:consequence> 用于設置推薦購買為 No 以外。我們再次運行測試,這次通過了。
       
        這時,如果你習慣于過程化編程(像大多數 Java 程序員一樣),你也許要搔頭皮了:在一個文件中包含兩個獨立的業務規則,而且我們也沒告訴規則引擎哪個更重要。不管怎樣,股票價格(對于 -22)都滿足兩個規則(也就是少于 0 和少于 100)。盡管這樣,我們仍能得到正確結果,即使交換規則順序。這是怎么做到的呢?
       
        下面的控制臺輸出有助于我們了解到底怎么回事。我們看見兩個規則都執行了([activationfired] 這行),Recommend Buy 第一次被設置為 Yes 接著又被設置成 No。Drools 怎么知道執行這些規則的正確順序呢?如果你觀察 Stock Price Low Enough 規則,將發現 recommendPurchase() 其中一個條件為空。通過這點,Drools 規則引擎足以判斷 Stock Price Low Enough 規則應該在 Stock Price Not Negative 規則之前執行。這個過程稱為 conflict resolution。
       
    FIRE RULES
    ----------
    [ConditionTested: rule=Stock Price Not Negative;
      condition=[Condition: stockOffer.getStockPrice()
      < 0]; passed=true; tuple={[]}]
    [ActivationCreated: rule=Stock Price Not Negative;
      tuple={[]}]
    [ObjectAsserted: handle=[fid:2];
      
    object=net.firstpartners.rp.StockOffer@16546ef]
    [ActivationFired: rule=Stock Price Low Enough;
       tuple={[]}]
    [ActivationFired: rule=Stock Price Not Negative;
       tuple={[]}]
    Name:MEGACORP Price: -22 BUY:YES
    Name:MEGACORP Price: -22 BUY:NO

        如果你是一名過程化程序員,無論你用怎樣聰明的方式考慮這些,你都不會完全相信。這就是為什么要進行單元/模擬器測試的原因:進行 "堅固的" JUnit 測試(使用一般 Java 代碼)確保規則引擎所作出的決定是按照我們所想要的路線進行。(不會花費大量金錢在無價值的股票上)同時,規則引擎的強大和伸縮性允許我們快速開發業務邏輯。
       
        稍后,我們將學習如何用更加精練的解決方案進行沖突處理。
       
    沖突結局方案

        現在業務伙伴被打動了,并且開始考慮進行選擇了。隨即他們遇到了個 XYZ 公司股票的問題,那么我們來實現新規則吧:只有 XYZ 公司股票低于 10 歐元才可購買。
       
        像以前一樣,添加測試到模擬器,接著在規則文件中包含新業務規則。首先在 BusinessRuleTest.java 中添加新方法:
       
     /**
     * Makes sure the system will buy stocks
     * of XYZ corp only if it really cheap
     */
    public void testXYZStockBuy() throws Exception{
           
      //Create a Stock with our simulated values
      StockOffer testOfferLow = new StockOffer();
      StockOffer testOfferHigh = new StockOffer();
                   
      testOfferLow.setStockName("XYZ");
      testOfferLow.setStockPrice(9);
      testOfferLow.setStockQuantity(1000);
                   
      testOfferHigh.setStockName("XYZ");
      testOfferHigh.setStockPrice(11);
      testOfferHigh.setStockQuantity(1000);
                   
      //Run the rules on it and test
      BusinessLayer.evaluateStockPurchase(
        testOfferLow);
      assertTrue("YES".equals(
        testOfferLow.getRecommendPurchase()));
                   
      BusinessLayer.evaluateStockPurchase(
        testOfferHigh);
      assertTrue("NO".equals(
        testOfferHigh.getRecommendPurchase()));            
    }

        接下來向 BusinessRules.drl 中添加新 <rule>:
       
      <rule name="XYZCorp" salience="-1">
       <!-- Parameters we pass to rule -->
       <parameter identifier="stockOffer">
         <class>StockOffer</class>
       </parameter>
       
       <java:condition>
         stockOffer.getStockName().equals("XYZ")
       </java:condition>
       <java:condition>
         stockOffer.getRecommendPurchase() == null
       </java:condition>
       <java:condition>
         stockOffer.getStockPrice() > 10
       </java:condition>
           
       <!-- What happens when the business
                                    rule is activated -->
       <java:consequence>
         stockOffer.setRecommendPurchase(
           StockOffer.NO); 
         printStock(stockOffer);
       </java:consequence>
      </rule>

        注意業務規則文件,在 rule name 后面,我們把 salience 設置成 -1(到目前為止了解的最低優先級)。大多數規則在系統中是沖突的,這意味著 Drools 必須為規則的執行順序做判斷,假設這些條件都與規則匹配。默認的判斷方式是:
           
        Salience:賦予的值。
        Recency:使用規則的次數。
        Complexity:首先執行有復雜值的特定規則。
        LoadOrder:規則載入的順序。
       
        如果沒有顯示的在規則中詳細指明,將會發生:
       
        XYZ 公司規則("當價格高于 10 歐元就不購買 XYZ 的股票")將先執行(Recommend Buy 標志被設置為 No)。
        接著更多的一般規則("購買所有 100 歐元以下的股票")被執行,把 Recommend Buy 標志設置為 yes。
       
        這會給我們一個不想要的結果。然而,一旦在范例中設置了 saliency 要素,最終的測試和業務規則將像預期的那樣順利運行。
       
        大多數時間,編寫清晰的規則和設置 saliency 將給 Drools 足夠信息以選擇合適的順序執行規則,有時我們想改變整個規則沖突處理方式。下面的例子說明了如何改變,告訴規則引擎首先執行最簡單的規則。要注意的是:改變沖突解決方案要小心,它可能從根本上改變規則引擎的行為。
       
      //Generate our list of conflict resolvers
      ConflictResolver[] conflictResolvers =
        new ConflictResolver[] {
          SalienceConflictResolver.getInstance(),
          RecencyConflictResolver.getInstance(),
            SimplicityConflictResolver.getInstance(),
            LoadOrderConflictResolver.getInstance()
        };
                   
      //Wrap this up into one composite resolver
      CompositeConflictResolver resolver =
        new CompositeConflictResolver(
          conflictResolvers);
                           
      //Specify this resolver when we load the rules
      businessRules = RuleBaseLoader.loadFromUrl(
        BusinessLayer.class.getResource(
          BUSINESS_RULE_FILE),resolver);

        我們的簡單應用由 JUnit 測試驅動,我們不必改變 Drools 處理規則沖突的方式。知道沖突解決方案怎樣運作是很有用的,尤其當你的應用為了迎合更復雜、更苛刻的需求時。
       
    結束
       
        本文示范了大部分程序員不得不面對的問題:怎樣安排復雜業務邏輯的順序。我們示范了一個使用 Drools 作為解決方案并引入基于規則編程概念的簡單應用,包括了怎樣在運行時處理規則。接著,后續文章使用這些技術并展示了怎樣在企業級 Java 應用中使用。


    請注意!引用、轉貼本文應注明原譯者:Rosen Jiang 以及出處:http://www.tkk7.com/rosen

    posted on 2005-09-12 22:11 笨笨 閱讀(2506) 評論(0)  編輯  收藏 所屬分類: J2EE 、ALL
    主站蜘蛛池模板: 精品亚洲成A人在线观看青青| 国产精品亚洲精品爽爽| 亚洲日韩精品无码专区加勒比| 中文字幕无码日韩专区免费| 成人免费夜片在线观看| 中文字幕在线免费观看| 亚洲成A∨人片天堂网无码| 国产色在线|亚洲| 2015日韩永久免费视频播放 | 1000部啪啪毛片免费看| 成人亚洲国产精品久久| 日本大片在线看黄a∨免费| 四虎必出精品亚洲高清| 91精品免费观看| 亚洲黄片手机免费观看| 亚洲AV伊人久久青青草原| 成年人视频在线观看免费| 亚洲国产成人va在线观看网址| 18女人腿打开无遮掩免费| 国产精品成人啪精品视频免费| 国产人成网在线播放VA免费| 在线观看亚洲av每日更新| 抽搐一进一出gif免费视频| 亚洲成a人片在线观看播放| 午夜男人一级毛片免费| 久久免费高清视频| 亚洲午夜在线播放| 亚洲精品中文字幕无乱码麻豆| 亚洲成_人网站图片| 亚洲熟妇久久精品| 日韩亚洲人成在线综合日本 | 亚洲AV无码成人精品区大在线| 亚洲成人影院在线观看| 亚洲网站在线观看| 国产精品亚洲不卡一区二区三区| 人妻无码一区二区三区免费| 中文字幕亚洲精品无码| 一级毛片大全免费播放| 亚洲av午夜电影在线观看 | 精品免费AV一区二区三区| 永久亚洲成a人片777777|