2017-06-26 69 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