充值促销的背后

1.背景

在绝大数游戏产品中,我们会看到各种充值赠送的类似活动,例如王者荣耀。在其他类产品中也会存在。

需求目的主要是为了保证产品流水,带来产品收入,与此同时给予用户其他满足感。

通过充值获得其他奖励,比如充值后,会有积分奖励。那么这部分积分可以兑换一些其他商品。

2.充值促销的业务分析

这里只对业务简单的分析:

  1. 在充值界面上,凸显充值赠送逻辑;
  2. 用户充值后会有对应充值奖励到帐;
  3. 充值策略包括每次充值,每天首次,累计充值等;
  4. 充值赠送不限于积分,快乐币,开心币等。
  5. 保证充值策略和赠送的可扩展性

图示1 (充值界面:Pinta不太会用,只能这样了)

3.方案规划

1)主要方向

	1.促销业务依赖与充值支付业务,最好不要影响原本充值业务性能

	2.后台可管理充值策略,便于运营运营策略

	3.充值后要保证,不可多送等情况

2)项目架构梳理:

本业务主要牵涉两个服务:1,支付系统 2,主要的各个业务系统。

图示2(整个支付架构与主要业务流程)

图示3

  1. 解决方案,

使用责任链模式来衔接普通充值和充值赠送策略业务,使用策略模式来判定赠送,用户充值完后异步判断是否满足促销条件,可以使用mq来解偶相关异步操作,插入充值促销获得记录,插入对应赠送的流水表(比如赠送快乐币)

业务系统接收到支付系统成功后,通过责任链来衔接普通充值和充值促销活动,当执行到促销业务逻辑时,通过获取在此之间运行的充值促销活动来判断执行充值的逻辑有哪些,执行逻辑中会有其他赠送逻辑,依旧使用策略模式去判断调用

图示3(划分逻辑),画图工具额)

4.数据库表的逻辑设计

充值促销活动配置表:

字段数据类型说明
idbigint(20)主键
titlevarchar(32)活动标题
iconvarchar(511)活动图标
descvarchar(255)描述
reward_typeint(11)赠送类型
reward_valuebigint(20)赠送数值
condition_valuebigInt(20)达到要求的数值
start_timedatatime开始时间
end_timedatatime结束时间
create_timedatatime创建时间
create_admin_idbigint(20)创建管理员id
is_deletetinyint(1)是否删除

记录表:

字段数据类型说明
idbigint(20)主键
user_idbigint(20)用户id
typeint(11)奖励类型
valuebigint(20)奖励数值
create_timedatatime创建时间
is_deletetinyint(1)是否删除

5.相关code

ps:记录一下( 害怕健忘)

/**
 * @author 易成贤
 * @Description 责任链模式下
 **/
@Slf4j
public abstract class PayCoin {

    /**
     * 记录下一条链子
     */
    private PayCoin next;

    /**
     * 适配业务币
     * @param payNoticeDto
     * @return
     */
    private final void handlerCoin(PayNoticeDto payNoticeDto) {
      
       	//todo 具体实现
       	
        //如果有下一条链子就继续进行处理
        if (Objects.nonNull(next)) {
            coinCount += next.handlerCoin(payNoticeDto);
        }
 
    }

    /**
     * 设置下一条链子
     */
    protected void setNext(PayCoin payHandler) {
        this.next = payHandler;
    }
}
/**
 * @author 易成贤
 * @Description TODO 上下文策略
 **/
@Service
public class RewardPayContext {

    @Resource
    private final Map<String, RewardPayStrategy> strategyMap = new ConcurrentHashMap<>();

    /**
     *
     * @param map
     */
    public RewardPayContext(Map<String, RewardPayStrategy> map){
        this.strategyMap.clear();
        map.forEach((k,v)->this.strategyMap.put(k,v));
    }

    /**
     * 获取策略
     * @param strategyId 策略对应的id
     * @return 对应的策略
     */
    public RewardPayStrategy getStrategy(String strategyId){
        return strategyMap.get(strategyId);
    }

}
/**
 * @author 易成贤
 * @Description TODO 策略 模式实现
 **/
public interface RewardPayStrategy {
    /**
     * 一系列操作
     */
   void todoString(CommonUserInfoDo commonUserInfoDo, PayNoticeDto payNoticeDto);
}