最近做一个企业团购相关的项目, 这两天有人也提出了有关业务规则的一些东西, 特别一些有关营销的业务, 比如送积分, 送券这些。假如我们要搞一些营销活动, 对一次性购买多少件或多少钱的用户送上一张面值不同的券, 放在平时, 可能马上就开个feature, 在下单后判断用户所支付的钱是否满足这个条件, 满足则送, 不满足就不送。 但是, 要是现在希望更吸引用户, 我要降低门槛, 或增大面值, 难道又开个Hotfix改这段逻辑?似乎不是没有道理, 但是, 世间变化的东西太多, 我们人太难预料和 把控, 那么如何去更好地认识这种问题呢?
这两天也想了又想, 到底要怎么才能更好地管理这些频繁变化的业务逻辑, 似乎自己想得太过于复杂, 或者想得不太清楚。现在想想, 似乎也有点点思路, 其实, 要把 这些业务完全抽象出来是不可能的, 总不能拍拍屁股就让程序去执行一段逻辑了吧。
现在是这样想的: 我们自己还是要从代码业务中抽离出这些经常执行上述逻辑的地方, 比如用户登录, 注册, 下单等。个人觉得我们要抽离的这些业务通常不会, 也不应该影响主逻辑, 比如送券, 不会送券没成功, 就不让用户下单吧, 这应该可以在程序中 记录这些, 重试发放, 或者若用户发现未送, 可以同运营客服进行沟通, 所以抽离逻辑也许应该放在事件中来处理比较合理, 至少对于现在项目这种情况还是可行的。
要是真不能很好地抽离这些逻辑, 那我们是否也能尽力能让编写这种类似逻辑变得更规范更统一些呢?
这两天, 也了解了下规则引擎相关的东西, 接触了下Java中的一门规则引擎Drools, 似乎看到了一丝希望, Drools允许我们事先编写一个规则脚本, 准备一些上下文信息, 注入到规则上下文中, 然后执行, 下面是一个官方模拟的火灾现场例子:
rule "When there is a fire turn on the sprinkler"
when
Fire($room : room)
$sprinkler : Sprinkler(room == $room, on == false)
then
modify($sprinkler){setOn(true)};
System.out.println("Turn on the sprinkler for room " + $room.getName());
end
rule "When the fire is gone turn off the sprinkler"
when
$room : Room()
$sprinkler : Sprinkler(room == $room, on == true)
not Fire(room == $room)
then
modify($sprinkler){setOn(false)};
System.out.println("Turn off the sprinkler for room " + $room.getName());
end
rule "Raise the alarm when we have one or more fires"
when
exists Fire()
then
insert(new Alarm());
System.out.println("Raise the alarm");
end
rule "Cancel the alarm when all the fires have gone"
when
not Fire()
$alarm : Alarm()
then
retract($alarm);
System.out.println( "Cancel the alarm" );
end
rule "Status output when things are ok"
when
not Alarm()
not Sprinkler(on == true)
then
System.out.println("Everything is ok");
end
// 房间
public class Room {
private String name; //房间名
// getter and setter
}
// 灭火器
public class Sprinkler {
private Room room; //所属房间
private boolean on; //是否打开
public Sprinkler(Room room){
this.room = room;
}
// getter and setter
}
// 火灾
public class Fire {
private Room room; //发生火灾的房间
// getter and setter
}
// 警报
public class Alarm {
}
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("rules/disaster.drl"), ResourceType.DRL);
if (kbuilder.hasErrors()) { //脚本是否有错误
System.err.println(kbuilder.getErrors().toString());
return;
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
//四个房间: 厨房, 卧室, 办公室, 客厅
String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String, Room> name2room = new HashMap<>();
for (String name : names) {
Room room = new Room(name);
name2room.put(name, room);
ksession.insert(room);
Sprinkler sprinkler = new Sprinkler(room);
ksession.insert(sprinkler); //将数据模型插入上下文
}
// Everything is ok
ksession.fireAllRules();
// kitchen and office is firing
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();
// fire is put out
ksession.retract( kitchenFireHandle )
ksession.retract( officeFireHandle );
ksession.fireAllRules();
ksession.dispose();
除了营销业务, 交易等业务也有可能出现这种问题, 比如不同类目的商品可能会有不同的交易流程, 普通商品基本在线支付交易流程大概就是: 买家创建订单-->买家支付-->卖家发货-->买家确认收货 但其他类目商品, 如保险, 汽车等, 可能需要先付定金, 再付尾款等, 所以交易流程也有必要规则化。