一个折扣券发放系统的设计思路

一个软件系统的开发绝对不是单纯的编码,甚至可以说编码是最不重要的环节(但它是必不可少的环节),就像在建房子的时候,码砖虽然必不可少,但绝对不是最重要的,这也是戏称程序员为码农的原因吧。
那么什么是重要的呢,是开始编码前的设计,正所谓磨刀不误砍柴工,谋定而动就是这个道理。前期好的设计绝对是好处多多,经过精心设计的系统一定结构清晰、方便维护、易于扩展的,这在很大程度上也能在后期减少编码量和节约人工成本。
那我们从零开始一个软件系统的开发时,要怎样去设计呢,概括起来,无外乎这几个步骤:

  1. 找到主线并确定支线
  2. 抽象出实体
  3. 画出实体关系图
  4. 找出变和不变
  5. 确定对外接口
  6. 应用各种场景检验设计合理性
  7. 性能考虑

以下就以一个折扣券发放系统的设计过程,来分别阐述具体怎么做。

一、折扣券发放系统需求

业务背景:

公司一个主营产品是为用户提供线上点餐服务的平台,现在需要通过给用户发放折扣券的方式来吸引更多用户使用产品。

业务场景:

1、中秋节进入平台的用户可领一张10元抵扣券,每个用户限领一次,总共发出去10000张券。
2、用户下单成功分享出去一个连接,里面包含5张2元券,其他用户访问连接可领一张券,每个用户限领一次,该活动发出去卡券总数量限制在20000张。
3、用户进入餐厅点餐界面,可以领取一张2元折扣券,该折扣券由餐厅承担。

二、找到主线并确定支线

任何系统要做什么,总能用一句话来概括出来,这就是业务的主线(也就是主流程)。
对于折扣券发放系统来说,它要做的就是,用户在某些条件和场合下能领到1或多张在某些条件下可以抵扣的折扣券。对于场景2来说,应该在发券之前,还需要一个创建一个券包的过程,所以总结起来,整个折扣券发放的主流程应该是:
1、用户或系统通过某种方式创建一个折扣券的包。
2、用户通过某种方式从上一步创建的折扣券包中,领取一张或多张折扣券。

至于围绕主线的支线,从业务场景中,我们可以分析出以下一些来:
1、用户得到券的条件:进入平台首页、进入餐厅点餐界面、点击连接等。
2、折扣券的面值有10元、2元等。
3、每个场景发放的折扣券总数量是可控的,比如中秋节活动总共发10000张券。
4、折扣券的成本是平台承担还是餐厅承担是可以设置的。
5、折扣券包的创建,可以是用户来创建,也可以是系统默认创建。
6、用户可以领券的次数可以设置,包括整个活动的可领次数和一个券包可领的次数。

三、实体抽象

经过对业务场景的分析,我们需要抽取出以下一些实体:
1、活动:一次发卡券的活动,比如这里的中秋节进系统就送卡券的活动
2、事件:用户的操作,比如场景中的进入系统首页和分享出去一个连接
3、卡券:就是场景中说到的折扣券,需要定义抵扣金额,使用条件,适用范围等属性
4、卡券包:包含卡券的一个包,比如场景中的一个连接包含5张2元券,这个连接就可以抽象出来为一个卡券包
5、卡券策略:定义了怎样将卡券发放到用户手中的程序,由于不同场景发放卡券的具体限制条件和流程等完全不同,所以卡券策略应该是一个方便扩展的一个对象,或者是一个jar包,也或者是一个微服务
6、策略属性:卡券策略程序中可变的参数(比如一个用户每天能领卡券的次数,不同活动有不同的定义),抽象出策略属性的概念是为了写出通用的卡券策略程序,这样不同的活动只要设置不同的策略属性值就能实现不同的卡券发放策略。

四、实体关系图

实体关系图也就是E-R图(也称实体-联系图),E-R图清楚地标识出了各个实体之间的关系。折扣券系统的E-R图如下:
在这里插入图片描述
对照以上的E-R图,我们来理一下折扣券发放的程序流程:
1、用户或平台触发事件
2、通过事件找到关联的所有活动
3、依次调用活动中绑定的策略程序进行创建券包和卡券发放实际操作
4、在策略程序中根据传入的活动信息找到相关的折扣券、券包、策略属性等相关信息进行实际操作
通过程序流程的梳理,我们也能得出各个实体之间的关系:
1、事件和活动之间是1对多的关系,一个事件可以触发多个活动,具体是否触发还得看活动的属性,比如活动是否可用,这样的属性设置可以方便控制活动的启停。
2、活动和策略程序是多对1的关系,策略程序可以做得通用一些,这样不同的活动都可以使用同一个程序,通过不同活动设置不同的策略属性值来达到定制不同的发卡方式的目的。
3、活动和策略属性值组是一对一的关系,一个活动都有一组特定的策略属性值来定制出一个特定的发卡策略。
4、策略和策略属性定义是多对多的关系,策略属性定义是公用的,具体到一个策略程序使用了哪些策略属性定义,就通过这个多对多的关系去设定。
5、活动和折扣券为1对多的关系,一个活动肯定有不止发放一个面值折扣券的需求。
6、活动和券包为1对多的关系,一个活动肯定会产生很多的券包,比如分享连接包含5张券的场景中,就会产生很多券包。
7、折扣券和券包之间是多对多的关系,一个面值的券可以在多个券包中,同样一个券包也可以包含多种面值的券。
8、券适用范围和券之间为1对多的关系,适用范围可以被多个折扣券使用,因为很多券的适用范围可能是一样的。
9、折扣券和使用条件之间为多对1的关系,和适用范围一样,很多券的使用条件可以是一样的。
10、券包和领券记录是1对多的关系,一个券包下的券肯定会被领取很多次。

五、找出变和不变

通过流程梳理以及实体关系的整理,我们可以得出这样的结论,在系统应用到不同场景时,唯一需要改变的就是策略,其他实体都可以固定下来。就是变的是策略程序,其他基本上都不会变,所以需要为策略程序提取一个接口,在适用不同场景时,对这个接口做不同的实现程序。

六、确定对外接口

通过前面的分析,其实整个发券的过程只两个过程,一个是券包的创建,一个是发券到用户账户。所以,对外接口就两个:
1、券包创建,参数应该包括事件、用户id(可能没有)、其他附带参数。
2、发折扣券,参数应该包括事件、用户id(可能没有)、券包id(可能没有)、其他附带参数。
另外,策略程序接口基本上与此相同。

七、应用各种场景检验设计合理性

场景1、中秋节进入平台的用户可领一张10元抵扣券,每个用户限领一次,总共发出去10000张券。
系统使用过程:
1、创建一个事件:IntoPlatform
2、创建活动,并绑定事件IntoPlatform
3、为活动添加折扣券,面值10元,适用范围全平台,使用条件为订单金额达到50元,折扣券总数量为10000
4、活动中添加券包,券包包含步骤3添加的折扣券
5、为活动选择策略程序
6、为活动设置策略属性领券次数为1
7、前端程序在用户进入平台时,调用折扣券系统的对外接口发折扣券
在这场景中,策略程序需要关注策略属性是,用户可以领券的次数,所以在发券时,需要从领券记录中查询用户的领券次数是否已经达标。另外,由于没有传入券包id,所以程序直接使用活动中已有的唯一的券包进行发券。

扫描二维码关注公众号,回复: 12272393 查看本文章

场景2、用户下单成功分享出去一个连接,里面包含5张2元券,其他用户访问连接可领一张券,每个用户限领一次,该活动发出去卡券总数量限制在20000张。
系统使用过程:
1、创建一个事件:ShareOrder
2、创建活动,并绑定事件ShareOrder
3、为活动添加折扣券,面值2元,适用范围全平台,使用条件为订单金额达到20元,折扣券总数量为20000
4、为活动选择策略程序
5、为活动设置策略属性领券次数为1,为活动设置策略属性一次领取数量为1
6、前端程序在用户分享连接时,调用折扣券系统的对外接口券包创建,将返回的券包id放到连接中
7、前端程序在用户点击分享出来的连接时,调用折扣券系统的对外接口发折扣券,传入连接中的券包id
在这场景中,策略程序需要关注策略属性有:
1、用户可以领券的次数
2、用户一次领取券数量

场景3、用户进入餐厅00100090的点餐界面,可以领取一张2元折扣券,该折扣券由餐厅00100090承担。
系统使用过程:
1、创建一个事件:InRestaurant
2、创建活动,并绑定事件InRestaurant
3、为活动添加折扣券,面值2元,适用范围餐厅00100090,使用条件为订单金额达到20元,折扣券总数量为0表示没有限制
4、活动中添加券包,券包包含步骤3添加的折扣券
5、为活动选择策略程序
6、为活动设置策略属性一次领取数量为1,为活动设置策略属性餐厅id为00100090
7、前端程序在用户进入点餐界面时,调用折扣券系统的对外接口发折扣券,通过附带参数传入餐厅id00100090
在这场景中,策略程序需要关注策略属性有:
1、用户可以领券的次数
2、餐厅id是不是00100090

以上三个场景,可以使用相同的策略程序,这个程序绑定3个策略属性:
1、领券次数
2、一次领取数量
3、餐厅id
程序中可以通过策略属性的值是否为空来决定是否关注该属性。

通过3个场景的应用,我们可以看到整个系统的设计是合理的,能适用各种场景,还可以很方便的通过实现不同的策略程序来进行扩展。

性能考虑

1、分布式部署,提高系统可用性。
2、热数据缓存到redis,比如当前进行中的活动相关数据缓存到redis。
3、通过消息队列,异步通知业务系统发券结果。

猜你喜欢

转载自blog.csdn.net/m0_46455711/article/details/111872796