流口水可执行模型
可執(zhí)行模型是對引擎處理的Drools最低級別模型的重新設(shè)計(jì)。 在當(dāng)前的系列(最多6.x)中,可執(zhí)行模型在過去的8年中有機(jī)地增長了,從未真正成為最終用戶的目標(biāo)。 建議那些希望以編程方式編寫規(guī)則的人通過代碼生成和目標(biāo)drl來完成; 這是不理想的。 從來沒有任何驅(qū)動程序可以使最終用戶更容易地使用它,因?yàn)樵贘ava中廣泛使用匿名類非常麻煩。 借助Java 8和Lambda的這種變化,就有可能制造出最終用戶可以訪問的更具吸引力的模型。
這個新模型是在高級語言的編譯過程中生成的,但是也可以單獨(dú)使用。 我們的目標(biāo)是使該可執(zhí)行模型自成一體,并避免進(jìn)行進(jìn)一步的字節(jié)碼修改(分析,轉(zhuǎn)換或生成); 從該模型的角度來看,所有內(nèi)容均由代碼或高級語言層提供。 例如,索引等必須由參數(shù)提供,高級語言在針對可執(zhí)行模型時會通過分析生成這些參數(shù)。
它旨在利用Java 8的lambda很好地映射到Fluent級別的構(gòu)建者。 這將使其對Java開發(fā)人員和語言開發(fā)人員更具吸引力。 而且,這將允許獨(dú)立于任何語言的低級引擎功能設(shè)計(jì)和測試。 這意味著我們可以在引擎級別進(jìn)行創(chuàng)新,而不必?fù)?dān)心語言層。
可執(zhí)行模型應(yīng)該足夠通用以映射到多個域。 這將是一個低級數(shù)據(jù)流模型,您可以在其中處理功能性反應(yīng)式編程模型,但仍可用于從中構(gòu)建基于規(guī)則的系統(tǒng)。
以下示例提供了用于構(gòu)建可執(zhí)行模型的流利DSL的第一個視圖:
DataSource persons = sourceOf(new Person("Mark", 37),new Person("Edson", 35),new Person("Mario", 40));Variable<Person> markV = bind(typeOf(Person.class));Rule rule = rule("Print age of persons named Mark").view(input(markV, () -> persons),expr(markV, person -> person.getName().equals("Mark"))).then(on(markV).execute(mark -> System.out.println(mark.getAge())) );前面的代碼定義了一個包含一些人員實(shí)例的數(shù)據(jù)源,并聲明了人員類型的變量markV。 規(guī)則本身包含通常的兩部分:LHS由傳遞給view()方法的一組輸入和表達(dá)式定義,而RHS是由傳遞給then()方法的lambda表達(dá)式定義的動作。
更詳細(xì)地分析LHS,語句如下:
input(markV, () -> persons)將人員數(shù)據(jù)源中的對象綁定到markV變量,并通過對象類進(jìn)行模式匹配。 從這個意義上講,DataSource可以被視為等同于Drools入口點(diǎn)。
相反的表達(dá):
expr(markV, person -> person.getName().equals("Mark"))使用謂詞定義綁定到markV變量的對象必須滿足的條件才能被引擎成功匹配。 請注意,正如預(yù)期的那樣,模式匹配的評估不是通過由任何種類的分析或編譯過程產(chǎn)生的約束來執(zhí)行的,而是僅通過應(yīng)用實(shí)現(xiàn)謂詞的lambda表達(dá)式來執(zhí)行(在這種情況下,人員- > person.getName()。equals(“ Mark”))匹配的對象。 換句話說,前一個DSL會生成一個規(guī)則的可執(zhí)行模型,該模型等效于后續(xù)drl的解析結(jié)果。
rule "Print age of persons named Mark" whenmarkV : Person( name == "Mark" ) from entry-point "persons" thenSystem.out.println(markV.getAge()); end它還正在開發(fā)一個rete構(gòu)建器,可以使用此DSL定義的規(guī)則。 特別是,可以將這些規(guī)則添加到CanonicalKieBase中,然后像其他任何普通KieBase一樣從中創(chuàng)建KieSession。
CanonicalKieBase kieBase = new CanonicalKieBase(); kieBase.addRules(rule);KieSession ksession = kieBase.newKieSession(); ksession.fireAllRules();當(dāng)然,DSL還允許定義更復(fù)雜的條件,例如連接:
Variable<Person> markV = bind(typeOf(Person.class)); Variable<Person> olderV = bind(typeOf(Person.class));Rule rule = rule("Find persons older than Mark").view(input(markV, () -> persons),input(olderV, () -> persons),expr(markV, mark -> mark.getName().equals("Mark")),expr(olderV, markV, (older, mark) -> older.getAge() > mark.getAge())).then( on(olderV, markV).execute((p1, p2) -> System.out.println(p1.getName() + " is older than " + p2.getName())) );或存在模式:
Variable<Person> oldestV = bind(typeOf(Person.class)); Variable<Person> otherV = bind(typeOf(Person.class));Rule rule = rule("Find oldest person").view(input(oldestV, () -> persons),input(otherV, () -> persons),not(otherV, oldestV, (p1, p2) -> p1.getAge() > p2.getAge())).then( on(oldestV).execute(p -> System.out.println("Oldest person is " + p.getName())) );這里的not()代表所有表達(dá)式的取反,因此上面使用的形式實(shí)際上只是以下內(nèi)容的快捷方式:
not( expr( otherV, oldestV, (p1, p2) -> p1.getAge() > p2.getAge() ) )還已經(jīng)以以下形式支持累計(jì):
Variable<Person> person = bind(typeOf(Person.class)); Variable<Integer> resultSum = bind(typeOf(Integer.class)); Variable<Double> resultAvg = bind(typeOf(Double.class));Rule rule = rule("Calculate sum and avg of all persons having a name starting with M").view(input(person, () -> persons),accumulate(expr(person, p -> p.getName().startsWith("M")),sum(Person::getAge).as(resultSum),avg(Person::getAge).as(resultAvg))).then(on(resultSum, resultAvg).execute((sum, avg) -> result.value = "total = " + sum + "; average = " + avg) );為了提供最后一個更完整的用例,可以使用此DSL定義經(jīng)典火災(zāi)和警報示例的可執(zhí)行模型,如下所示。
Variable<Room> room = any(Room.class); Variable<Fire> fire = any(Fire.class); Variable<Sprinkler> sprinkler = any(Sprinkler.class); Variable<Alarm> alarm = any(Alarm.class);Rule r1 = rule("When there is a fire turn on the sprinkler").view(input(fire),input(sprinkler),expr(sprinkler, s -> !s.isOn()),expr(sprinkler, fire, (s, f) -> s.getRoom().equals(f.getRoom()))).then(on(sprinkler).execute(s -> {System.out.println("Turn on the sprinkler for room " + s.getRoom().getName());s.setOn(true);}).update(sprinkler, "on") );Rule r2 = rule("When the fire is gone turn off the sprinkler").view(input(sprinkler),expr(sprinkler, Sprinkler::isOn),input(fire),not(fire, sprinkler, (f, s) -> f.getRoom().equals(s.getRoom()))).then(on(sprinkler).execute(s -> {System.out.println("Turn off the sprinkler for room " + s.getRoom().getName());s.setOn(false);}).update(sprinkler, "on") );Rule r3 = rule("Raise the alarm when we have one or more fires").view(input(fire),exists(fire)).then(execute(() -> System.out.println("Raise the alarm")).insert(() -> new Alarm()) );Rule r4 = rule("Lower the alarm when all the fires have gone").view(input(fire),not(fire),input(alarm)).then(execute(() -> System.out.println("Lower the alarm")).delete(alarm) );Rule r5 = rule("Status output when things are ok").view(input(alarm),not(alarm),input(sprinkler),not(sprinkler, Sprinkler::isOn)).then(execute(() -> System.out.println("Everything is ok")) );CanonicalKieBase kieBase = new CanonicalKieBase(); kieBase.addRules(r1, r2, r3, r4, r5);KieSession ksession = kieBase.newKieSession();// phase 1 Room room1 = new Room("Room 1"); ksession.insert(room1); FactHandle fireFact1 = ksession.insert(new Fire(room1)); ksession.fireAllRules();// phase 2 Sprinkler sprinkler1 = new Sprinkler(room1); ksession.insert(sprinkler1); ksession.fireAllRules();assertTrue(sprinkler1.isOn());// phase 3 ksession.delete(fireFact1); ksession.fireAllRules();在此示例中,可能還要注意幾件事:
- 必須執(zhí)行一些重復(fù)操作才能將表達(dá)式的參數(shù)綁定到評估它的lambda表達(dá)式的形式參數(shù)。 希望可以在解決此JDK錯誤時使用-parameters編譯參數(shù)來克服此問題。
- any(Room.class)是bind(typeOf(Room.class))的快捷方式
- 輸入未聲明數(shù)據(jù)源。 這是指出這些對象來自默認(rèn)空DataSource的快捷方式(對應(yīng)于Drools默認(rèn)入口點(diǎn))。 實(shí)際上,在此示例中,事實(shí)以編程方式插入到KieSession中。
- 使用輸入而不為其提供任何表達(dá)式的輸入實(shí)際上是input(alarm),expr(alarm,a-> true)的快捷方式
- 以同樣的方式,沒有條件的存在模式,例如not(fire)是not(expr(fire,f-> true))的另一個快捷方式
- Java 8語法還允許將謂詞定義為訪問諸如expr(sprinkler,Sprinkler :: isOn)之類的事實(shí)的布爾屬性的方法引用。
- RHS與要執(zhí)行的代碼塊一起,還提供了一個流暢的接口來定義在觸發(fā)規(guī)則時必須執(zhí)行的工作內(nèi)存操作(插入/更新/刪除)。 特別是,更新還獲得了一個字符串變量,用于報告在更新的事實(shí)中更改過的屬性的名稱,例如update(sprinkler,“ on”)。 再次必須明確提供此信息,因?yàn)楸仨殑?chuàng)建可執(zhí)行模型而無需任何代碼分析。
翻譯自: https://www.javacodegeeks.com/2014/07/drools-executable-model.html
總結(jié)
- 上一篇: 电脑怎么用手机网络上网手机如何利用电脑上
- 下一篇: 外汇游乐场