大家好:
通过第一天的学习大家对于Drools的安装已经有一个初步的了解,接下来我们将进一步对drools的算法进行学习。
rule "name"
attributes
when
LHS
Then
RHS
End
从代码 中可以看到,一个规则通常包括三个部分:属性部分(attribute)、条件部分(LHS)和结果部分(RHS)。对于一个完整的规则来说,这三个部分都是可选的。即:
也是完全正确的。
1. 条件部分
条件部分又被称之为Left Hand Side,简称为LHS,下文当中,如果没有特别指出,那么所说的LHS 均指规则的条件部分,在一个规则当中when 与then 中间的部分就是LHS 部分。在LHS 当中,可以包含0~n 个条件,如果LHS 部分没空的话,那么引擎会自动添加一个eval(true)的条件,由于该条件总是返回true,所以LHS 为空的规则总是返回true。LHS 部分是由一个或多个条件组成,条件又称之为pattern(匹配模式),多个pattern之间用可以使用and 或or 来进行连接,同时还可以使用小括号来确定pattern 的优先级。
一个pattern 的语法如下: [绑定变量名:]Object([field 约束])
对于一个pattern 来说“绑定变量名”是可选的,如果在当前规则的LHS 部分的其它的pattern 要用到这个对象,那么可以通过为该对象设定一个绑定变量名来实现对其引用,对于绑定变量的命名,通常的作法是为其添加一个“$”符号作为前缀,这样可以很好的与Fact的属性区别开来;绑定变量不仅可以用在对象上,也可以用在对象的属性上面,命名方法与对象的命名方法相同;“field 约束”是指当前对象里相关字段的条件限制,示例如下:
此段规则的定义如下:
规则名“check”
When部分为条件部分$i:InsurantInfo(age > 18 , gender == "female");
首先遍历InsurantInfo对象,找出所有InsurantInfo中符合条件年龄大于18,性别为female的。
之后判断$p:PolicyInfo(insurantInfo == $i);
遍历PolicyInfo找出所有PolicyInfo中有和这个对象一致的对象,如果有就将PolicyInfo信息输出。
2. 约束连接
对于对象内部的多个约束的连接,可以采用“&&”(and)、“||”(or)和“,”(and)来实现,代码清单中规则的LHS 部分的两个pattern 就里对象内部约束就采用“,”来实现,“&&”(and)、“||”(or)和“,”这三个连接符号如果没有用小括号来显示的定义优先级的话,那么它们的执行顺序是:“&&”(and)、“||”(or)和“,” “&&”优先级最高,表面上看“,”与“&&”具有相同的含义,但是有一点需要注意,“,”与“&&”和“||”不能混合使用,也就是说在有“&&”或“||”出现的LHS 当中,是不可以有“,”连接符出 现的,反之亦然。
3. 比较操作符
在Drools5当中共提供了十二种类型的比较操作符,分别
是:>、>=、<、<=、= =、!=、contains、not contains、memberof、not memberof、matches、not matches;在这十二种类型的比较操作符当中,前六个是比较常见也是用的比较多的比较操作符,着重对后六种类型的比较操作符进行介绍。
如下例所示:
判断insurantInfos中是否包含有一个符合条件的insurantInfo。
Drools不人性化部分,对象都需要插入到Ksession中。
4. 案例分析
在最后我们列出一个具体的事例来说明drools语言,通过这个例子我们可以看到在不同场景下规则执行的情况。
案例背景:火警报警系统。
当没有发生火警的时候,会报告一切ok。
当出现火警的时候,会自动打开消火栓进行灭火。
当火情消灭的时候,会关闭消火栓。
模型:
//房屋。参数:房屋名称
public static class Room {
private String name;
public Room(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
// getter and setter methods here
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//消防灭火器。参数:对象房屋、警报是否打开
public static class Sprinkler {
private Room room;
private boolean on;
public Sprinkler(Room room) {
// TODO Auto-generated constructor stub
this.room = room;
}
// getter and setter methods here
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
}
//火情。参数:对象房屋
public static class Fire {
private Room room;
// getter and setter methods here
public Fire(Room room) {
// TODO Auto-generated constructor stub
this.room = room;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
}
//警报
public static class Alarm {}
规则:
rule "Raise the alarm when we haveone or more fires"
when
exists Fire();
then
System.out.println( "Raise the alarm");
insert(new Alarm());
end
rule "When there is a fire turn onthe sprinkler"
when
Fire($room : room)
$sprinkler : Sprinkler( room == $room,on == false )
then
System.out.println( "Turn on the sprinkler for room" +$room.getName() );
modify( $sprinkler ) { setOn( true ) };
end
rule "Cancel the alarm when all thefires have gone"
when
not Fire();
$alarm : Alarm();
then
System.out.println( "Cancel the alarm" );
delete( $alarm );
end
rule "When the fire is gone turn offthe sprinkler"
when
$room : Room( )
$sprinkler : Sprinkler( room == $room,on == true )
not Fire( room == $room )
then
System.out.println( "Turn off the sprinkler forroom " + $room.getName());
modify( $sprinkler ) { setOn( false ) };
end
rule "Status output when things areok"
when
not Alarm()
not Sprinkler( on == true )
then
System.out.println( "Everything is ok" );
End
场景执行:
1. 一切OK
//初始化房屋和灭火器
String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String,Room> name2room = new HashMap<String,Room>();
for( String name: names ){
Roomroom = new Room(name);
name2room.put( name, room );
Ksession.insert( room );
Sprinkler sprinkler = new Sprinkler(room);
Ksession.insert( sprinkler );
}
Ksession.fireAllRules();
出现结果:Everything is ok
2. 出现火情
//出现火情
Fire kitchenFire = new Fire( name2room.get( "kitchen" ) );
Fire officeFire = new Fire( name2room.get( "office" ) );
FactHandle kitchenFireHandle =Ksession.insert( kitchenFire );
FactHandle officeFireHandle =Ksession.insert( officeFire );
Ksession.fireAllRules();
出现结果:
Raisethe alarm
Turnon the sprinkler for room kitchen
Turnon the sprinkler for room office
3. 扑灭火情:
//关闭火情
Ksession.delete( kitchenFireHandle );
Ksession.delete( officeFireHandle );
Ksession.fireAllRules();
出现结果:
Raisethe alarm
Turnon the sprinkler for room kitchen
Turnon the sprinkler for room office
Cancelthe alarm
Turnoff the sprinkler for room kitchen
Turnoff the sprinkler for room office
Everythingis ok