一些和规则相关的东西

JerryXia 发表于 , 阅读 (0)

最近做一个企业团购相关的项目, 这两天有人也提出了有关业务规则的一些东西, 特别一些有关营销的业务, 比如送积分, 送券这些。假如我们要搞一些营销活动,对一次性购买多少件或多少钱的用户送上一张面值不同的券, 放在平时, 可能马上就开个feature, 在下单后判断用户所支付的钱是否满足这个条件, 满足则送, 不满足就不送。但是, 要是现在希望更吸引用户, 我要降低门槛, 或增大面值, 难道又开个Hotfix改这段逻辑?似乎不是没有道理, 但是, 世间变化的东西太多, 我们人太难预料和把控, 那么如何去更好地认识这种问题呢?

这两天也想了又想, 到底要怎么才能更好地管理这些频繁变化的业务逻辑, 似乎自己想得太过于复杂, 或者想得不太清楚。现在想想, 似乎也有点点思路, 其实, 要把这些业务完全抽象出来是不可能的, 总不能拍拍屁股就让程序去执行一段逻辑了吧。

现在是这样想的: 我们自己还是要从代码业务中抽离出这些经常执行上述逻辑的地方,比如用户登录, 注册, 下单等。个人觉得我们要抽离的这些业务通常不会, 也不应该影响主逻辑, 比如送券, 不会送券没成功, 就不让用户下单吧, 这应该可以在程序中记录这些, 重试发放, 或者若用户发现未送, 可以同运营客服进行沟通, 所以抽离逻辑也许应该放在事件中来处理比较合理, 至少对于现在项目这种情况还是可行的。

要是真不能很好地抽离这些逻辑, 那我们是否也能尽力能让编写这种类似逻辑变得更规范更统一些呢?

这两天, 也了解了下规则引擎相关的东西, 接触了下Java中的一门规则引擎Drools, 似乎看到了一丝希望,Drools允许我们事先编写一个规则脚本, 准备一些上下文信息, 注入到规则上下文中, 然后执行, 下面是一个官方模拟的火灾现场例子:

drl脚本文件:

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());endrule "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());endrule "Raise the alarm when we have one or more fires"when    exists Fire()then    insert(new Alarm());    System.out.println("Raise the alarm");endrule "Cancel the alarm when all the fires have gone"when    not Fire()    $alarm : Alarm()then    retract($alarm);    System.out.println( "Cancel the alarm" );endrule "Status output when things are ok"when    not Alarm()    not Sprinkler(on == true)then    System.out.println("Everything is ok");end            

对应的java模型数据类:

// 房间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 okksession.fireAllRules();// kitchen and office is firingFire 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 outksession.retract( kitchenFireHandle )ksession.retract( officeFireHandle );ksession.fireAllRules();ksession.dispose();        

结果也正如规则中的描述一样:

drools.jpg

除了营销业务, 交易等业务也有可能出现这种问题, 比如不同类目的商品可能会有不同的交易流程, 普通商品基本在线支付交易流程大概就是:买家创建订单-->买家支付-->卖家发货-->买家确认收货但其他类目商品, 如保险, 汽车等, 可能需要先付定金, 再付尾款等,所以交易流程也有必要规则化。