最近在做购物车时,遇到一个挺让人纠结的场景:不同的商城都基于半产品化的项目A做二次开发和定制,在项目A中,需要做一个下单的功能,既然要下单肯定有加入购物车这个动作,加购物势必会有各种不同的验证,比如:库存校验,限购校验,购物车商品数量校验.......,不同的校验需要返回不同的状态。商城自己也可以做定制,因此,基于责任链模式来设计购物车的校验器是比较合适的!
那我们来看看怎么设计:
1.责任链肯定需要一个链,首先,我们定义一个ValidatorChain,这个类一个静态常量map,和另外一个成员变量index并赋初始值0,
一个静态方法,其作用是往map中注册校验器,如图:
validateMap 中key为校验器作用域,值为校验器集合
成员变量index 为执行校验时 执行的位置。
静态方法registValidator接受两个参数,一个是校验器的作用域,另外一个是校验器的实例。
另外一个方法,在这里先不做介绍,我们先看校验器:
抽象类AbstractManualOrderShoppingCartValidator中有两个方法:
抽象方法是子类需要继承实现的,也即校验器最终执行的方法,静态方法execute中,执行两个操作,首先执行校验器实例的volidate方法,执行成功接着回调ValidatorChain的doChain方法。此时我们来看看 这个doChain方法做了哪些事情:
首先是判空,然后根据传入的参数scope获得该作用域下的所有校验器实例集合,如果当前成员变量index小于校验器实例集合的size,则index 加1 ,并执行我们校验器抽象类的execute方法,该方法接受四个参数,一个是校验器链的实例,校验器实例,购物车商品集合,和需要校验的参数配置,而在校验器中我传入的第一个参数是this,那么当我们回调的时候,this.index 做了加1操作,一直执行直到index >= 校验器集合的size,从而实现购物车校验像一条链子一样向下执行校验。
解释完这个链,继续看我们怎么把装载校验器到责任链的validateMap中:
我们需要自定义一个注解ValidateScope,
这个注解两个目的:校验器用该注解标注之后,spring会把该校验器的实例丢到map中,注解接受一个作用域参数:
spring 启动将ValidateScope标注的校验器调用ValidatorChain.registValidator map中。完成校验器的初始化。
然后我们来看下这个购物车校验怎么调用:
加入购物车之前校验一次,加入购物车之后再校验一次。这样,商城只需继承校验器抽象类,实现校验方法,同时用ValidateScope标注,即可。