一些和规则相关的东西
2015 年 01 月 28 日
java

    最近做一个企业团购相关的项目, 这两天有人也提出了有关业务规则的一些东西, 特别一些有关营销的业务, 比如送积分, 送券这些。假如我们要搞一些营销活动, 对一次性购买多少件或多少钱的用户送上一张面值不同的券, 放在平时, 可能马上就开个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());
    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
                
  • 对应的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 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();
            
  • 结果也正如规则中的描述一样:

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

好人,一生平安。