drools规则引擎可以实现规则之间的相互调用吗_电商系统促销模块脚本引擎的应用...

本文探讨电商系统中促销模块的架构设计,指出传统架构存在的耦合问题,并提出基于脚本引擎(如drools)的解耦方案。通过定义规则和规范,实现促销逻辑与其他模块的隔离,提高扩展性和灵活性。以Javashop电商系统为例,介绍了规则模板、脚本生成和执行过程,强调了面向规则架构在电商领域的应用价值。
摘要由CSDN通过智能技术生成

背景介绍

    在电商系统中,促销模块主要架构特点在于促销活动的多种多样,比如常见的优惠券、满减满送、秒杀拼团等等等,另外一个特点是促销活动的多变性,促销活动要随着运营的需要而及时演化。

    基于以上特点,一个优秀的电商系统的促销模块他的架构应该做到两点:

  1. 促销模块和购物车订单的解耦

  2. 良好的扩展性

    本文以Javashop电商系统中的架构为例,详细讲解如何基于脚本引擎实现一个具有松散的、良好扩展性的促销模块。

难点分析     

我们先看一下如果不是基于脚本引擎的促销模块,和其他模块的耦合实例,以便我们理解应用脚本引擎后的好处。

1、领域模型的耦合

拿购物车列表来举例,为了计算、显示购物车中的促销情况,伪代码如下:

//每个店铺一个购物车,循环处理for (Cart cart : itemList) {   List productList = cart.getProductList();   for (Sku goods : productList) {       //计算购物车商品的促销活动       countSkuPormotion(goods);   }   //计算每个购物车的优惠(如店铺级别的满减满赠等)   countCartPromotion(cart)}

那么购物车和商品必然要和促销的领域模型耦合(如满减满赠、优惠卷等实体类):

购物车的伪代码:

public class Cart {     //店铺id     private int seller_id;     //购物车中的sku列表     private List skuList;     //购物车中使用的优惠券     private List couponList;     //赠品列表     private List giftList;     //赠送积分     private int giftPoint;     //其他略。。一大堆的促销模块的实体类。。。。}

同样的,购物车中的sku也要和促销领域模型进行耦合

public class Sku {     //店铺id     private int sku_id;     //商品sku名称     private String sku_name     //购物车中使用的优惠券     private List couponList;     //赠品列表     private List giftList;     //赠送积分     private int giftPoint;     //其他略。。一大堆的促销模块的实体类。。。。}

2、促销逻辑的耦合

促销的计算必然要调用到促销模块的业务类,比如计算购物车的促销情况:

void countCartPromotion(Cart cart){   //调用优惠券业务类,计算购物车的优惠券情况   couponService.count(cart);   //调用赠品业务类,计算购物车的赠品情况   giftService.count(cart);   //其他略。。。一大堆的各种促销业务类的调用}

其他模块也是如此

综和上述的耦合情况,如果促销领域模型发生变化,或促销业务类发生变化,其他模块如购物车、订单都需要跟随这些变化而变化,这对于开发者来讲是一个不小的灾难,促销模块和其他模块不是同一个人负责开发,开发过程中促销模块模型、参数需要频繁的沟通协调,也增加了开发难度,也很不利与促销模块的扩展。

架构思路

Javashop电商系统的架构思路是“面向规则”,用规则将促销模块和其他模块解耦,经过多年的经验,我们总结出促销的规则无非减价格或送东西(赠品、优惠券等)。首先我们建立类似如下的规则:

/***促销规则*/public class PromotionRule{    //活动的名称、标题,在界面中显示给用户用    private String title;    //促销规则:减价、送东西    private int ruleType;    //要减掉的金额    private double discount;}

基于上述规则,在架构上促销模块和其他模块隔离开:

23e15889349ea93eaa4e8675c7948d37.png

在Javashop中这个规则的运转就是基于脚本引擎的,在详细深入之前,我们先来熟悉一下Java中的脚本引擎

核心原理

在Java6以后就已经内置了ScriptEngine,可以支持Javascript脚本的解析执行,简单示例如下:

ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("javascript");//执行脚本String script ="funciton test() { return 'hello'; }";//设置一些可以使用的变量参数engine.put("somekey", "somevalue");//解析执行脚本engine.eval(script);//调用test functionInvocable invocable = (Invocable) engine;Object value = invocable.invokeFunction("test");

我们再看一下Javashop中定义的“满减满送”脚本(满减的门槛是100元),方便大家更好的理解:

//满减的functionfunction countPrice() {    //判断商品金额是否满足优惠条件     if (100 <= price) {        return  price - 5 ;    }    return price;}//满送的functionfunction giveGift() {    // 判断商品金额是否满足优惠条件    if (100 <= price) {        //返回赠品的json        return {giftid:1,name:'一个赠品'};    }    return null;}

以购物车为例,在Java中调用如下:

//设置价格变量engine.put("price", cart.getPrice() );engine.eval(script);//尝试调起减价functionDouble price = (Double)engine.invokeFunction("countPrice");//尝试调起“送东西” functionString giftJson = (String)engine.invokeFunction("giveGift");//形成促销规则PromotionRule rule = new PromotionRule()rule.setTile("某某活动");rule.setDiscount(price);rule.setGiftJson(giftJson);//接下来其他模块就面向 rule 去处理自己的逻辑了applyCartRule(cart,rule)

规则的定义和生成

细心的同学可能已经发现,上述脚本中的门槛(100元)还没有“动”起来,这就涉及到脚本的定义和生产了,其实“规则”就是脚本的算法,需要动起来的“变量”是某个活动运营人员定义的,具体的脚本只有在活动生效是才会真正生成出来,流程是这样子的:

51d079820a131678050ae16ae8bf5c1a.png

脚本的模板可以采用很多种技术,如freemaker、thymeleaf等等,在javashop中我们采用的是freemaker,举例:

function countPrice() {        if (${promotionActive.fullMoney} <= $price) {        var resultPrice = $price;        if (${promotionActive.isFullMinus} == 1) {            resultPrice = $price - ${promotionActive.minusValue};        }        return resultPrice < 0 ? 0 : resultPrice.toString();    }    return $price;}

运营人员定义了活动具体的门槛,当活动生效后,通过freemaker解析后的脚本就是具体的可执行的脚本了:

Promotion promotionActive = getPromotionFromDb(someID);Map params = new HashMap();//把当前活动压入freemarker上下文参数中,以便解析具体的值。params.put("promotionActive",promotionActive);Stirng script = freemarkerUtil.parse(ruleTplFile,params);

script结果如下:

//满减的functionfunction countPrice() {    //判断商品金额是否满足优惠条件     if (100 <= price) {        return  price -5 ;    }    return price;}

规范的定义

通过上述的架构思路,不难看出,我们还需要定义一套脚本的变量名称、方法名称的规范,以便其他模块调起脚本,和促销模块交互,比如定义如下规则:

1、变量规范:

变量名称

类型

说明

$currentTime

int

当前时间,为了验证活动是否有效

$sku

Object

商品的sku

$price

double

其他优惠活动优惠后总价

2、方法规范

满减满赠、优惠券促销活动脚本方法

方法名

返回值类型

返回值说明

validTime

Boolean

是否在有效期

countPrice

Double

计算减价金额

giveGift

Object

计算赠送物品

有了如上规范,其他模块就可以完成具体脚本的调起、计算了:

//设置规范中定义的变量engine.put("$currentTime", getCurrentTime );engine.put("$price", getCartPrice() );//等等...根据不同的业务逻辑,根据规范适当的传入变量。engine.eval(script);//尝试调起减价functionDouble price = (Double)engine.invokeFunction("countPrice");//根据规范调起其他方法...

总结

fb5b5b8aa9f6174b37308e293e81ff40.png

综上所述,架构的核心是定义了一套模块之间交互的规则:

  • PromotionRule(促销规则模型)

  • 脚本规范

  • 脚本

本着单一职责的原则,进而抽象促销模块和其他模块的功能边界:

  • 促销模块负责:定义脚本模板、生成存储脚本

  • 其他模块:调起脚本、生成促销规则、应用规则。

这样就完成了促销模块和其他模块的解耦,促销模块的领域模型和业务类不再侵入其他模块的代码中,双方的交互是面向的“规则”,互相都比较灵活,比如“减多少钱,怎么减?”购物车不需要关系,只关心规则应用后如何显示给用户,而促销模块也不用关心“能不能减价?如何显示给用户”类似的问题。而且基于规则的扩展也是非常方便的,只需要写相应的脚本模板就行了。

当然实际的实现要再复杂一些,比如脚本如何存储、活动生效钩子的实现,以及sku级别、店铺级别、购物车级别的规则和脚本如何定义存储等等,因为篇幅的原因还有很多细节无法一一详细列出,在这里抛砖引玉,提供大家一种“面向规则”架构的思路,上述架构思路其实不仅仅可以应用在电商领域,希望可以给有需要的同学一点帮助、开阔思路。

在最后给自己的产品打个广告:Javashop电商系统是易族智汇10多年打磨积累的的一套电商系统,前后端分离,有spring boot基础架构的版本也有微服务架构的版本。

  • 我们的优势:

功能丰富、架构优良、代码精致、文档齐全、易于二次开发

  • 提供的服务:

部署实施、全面架构培训、二次开发培训、二开一对一问题解答

  • 我们的产品涵盖:

模式上:b2b2c/b2c/o2o/b2b/saas,终端上:PC/WAP/小程序/APP

  • 我们的案例:

吉利集团、新奥集团、安琪酵母集团、山东京博集团、波司登....

如果您公司有相关电商的业务,基于Javashop来二次开发会大大提升效率、降低开发成本,如果向公司推荐成功采购,凭渠道码给您个人返现5000元。

渠道优惠码:【JAVASHOP-MP-NWTVWO39】

也欢迎您关注我们的公众号,上面会经常分享一些架构思路。

7f1df0f26eff52eb9dbf384b58c4e15e.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值