2017-06-26 68 views
0

我想設計一個規則引擎來過濾傳入的對象如下過濾多個輸入物體類是動態的,也就是說:我想擴展這個與D,E等類一起工作,如果D和E將在後面添加。規則引擎根據多個條件

public class A { 
    int a1; 
    String a2; 
    boolean a3; 
    Date a4; 
    List<String> a5; 
    ... 
} 

public class B { 
    String b1; 
    boolean b2; 
    Date b3; 
    long b4; 
    ... 
} 

public class C { 
    String c1; 
    boolean c2; 
    Date c3; 
    long c4; 
    ... 
} 

將有我的規則引擎將過濾的類A,B或C的不同對象。

用戶可以根據一組類的每個成員變量可能具有的預定義操作來定義不同的規則。

一些操作的一個例子:

  • A1可具有類似操作:> =,< =,或一些範圍之間,等等
  • A2可具有操作,如:不是,或者是,等等。
  • a3只能是真或假。
  • A4可以是:特定的日期,特定日期之後,或之間,前等
  • A5可以是:存在或不存在於列表中,對等的一個目的

一些示例規則A類是:

  • a1爲0和100之間,和a2不是 「ABC」,和A3是假的,和A4在今天之前,和A5包含 「CDF」 等
  • A2是「abc」,a3是真實的,a4是在某個日期範圍之間。

一顆子彈是一個規則。一般來說,可以有一個標準或更多的標準(多個標準是AND的組合)。

每個標準由一個成員變量定義,其中可以應用該變量的操作。

規則引擎必須能夠處理由用戶爲A,B或C類的每個對象定義的規則。對於進入的每個規則(A規則,B規則或C規則),返回將是符合指定規則的對象列表。

我可以創建Criterion,Criteria,ARule,BRule,CRule,Operation對象等;我可以用蠻力的方式去做事;但如果......其他......陳述會很多。

我很欣賞任何設計模式/設計方法的所有想法,我可以使用它來使這個清潔和可擴展。

非常感謝您的時間。

+0

也許你需要看的Drools:https://www.drools.org/。 – tsolakp

+0

規則在代碼中,還是需要將它們存儲在某個地方?即文本文件,數據庫等 –

+0

@tsolakp:我想自己開發這個小型引擎。感謝您的建議。 – Budzu

回答

1

聽起來像一條規則,實際上是由構成的Predicate-其他謂詞。使用Java 8,可以讓用戶定義謂詞的屬性:

Predicate<A> operationA1 = a -> a.getA1() >= 10;   // a1 is int 
Predicate<A> operationA2 = a -> a.getA2().startsWith("a"); // a2 is String 
Predicate<A> operationA3 = a -> a.getA3(); // == true;  a3 is boolean 

Predicate<A> ruleA = operationA1.and(operationA2).and(operationA3); 

現在,您可以流您List<A>,過濾和收集到一個新的列表:

List<A> result = listOfA.stream() 
    .filter(ruleA) 
    .collect(Collectors.toList()); 

您可以使用類似的方法進行BC

現在,有幾種方法可以抽象出所有這些。這裏是一個可能的解決方案:

public static <T, P> Predicate<T> operation(
     Function<T, P> extractor, 
     Predicate<P> condition) { 

    return t -> condition.test(extractor.apply(t)); 
} 

此方法創建一個謂語(即代表你的操作之一)根據Function將提取要麼ABC(或未來的類)的屬性和一個Predicate在那個屬性上。

對於我上面顯示的同樣的例子,你可以使用這種方式:

Predicate<A> operation1A = operation(A::getA1, p -> p >= 10); 
Predicate<A> operation2A = operation(A::getA2, p -> p.startsWith("a")); 
Predicate<A> operation3A = operation(A::getA3, p -> p); // p == true ? 

但是,因爲該方法是通用的,你也可以用它的B實例:

Predicate<B> operation1B = operation(B::getA1, p -> p.startsWith("z")); 
Predicate<B> operation2B = operation(B::getA2, p -> !p); // p == false ? 
Predicate<B> operation3B = operation(B::getA3, p -> p.before(new Date())); 

現在,您已經定義了一些操作,你需要一個通用的方法,從操作創建一個規則出來:

public static <T> Predicate<T> rule(Predicate<T>... operations) { 
    return Arrays.stream(operations).reduce(Predicate::and).orElse(t -> true); 
} 

此方法通過創建規則 - 執行給定的操作。它首先從給定數組創建一個流,然後通過將Predicate#and方法應用於操作來減少此流。您可以查看Arrays#streamStream#reduceOptional#orElse文檔瞭解詳情。

因此,創建A規則,你可以這樣做:

Predicate<A> ruleA = rule(
    operation(A::getA1, p -> p >= 10), 
    operation(A::getA2, p -> p.startsWith("a")), 
    operation(A::getA3, p -> p)); 

List<A> result = listOfA.stream() 
    .filter(ruleA) 
    .collect(Collectors.toList()); 
+0

非常感謝您的及時回覆。這對我來說是一個好開始。但是,如何將規則對象與您提出的設計相關聯?我想命名規則,然後列出與每個規則關聯的條件,以便我可以將規則保存到數據庫並稍後加載以供重用。 – Budzu

+1

@Steven嗨!那麼,你可以有'Criteria'和'Rule'類來實現'Predicate',或者你可能在這些類中有一個'Predicate'類型的屬性。當然,這些類也可以有'name'屬性。而'Rule'類可以有'List 條件'等屬性...... –

+1

非常感謝您的回答。 – Budzu