【设计模式】策略模式和抽象模板实现权益发放

应用场景

日常开发中,遇到这样一个场景:做一个用户会员权益发放模块,权益的类型可能有:平台积分、礼包、优惠券、支付卷、红包、兑换码、爱奇艺会员兑换码等;这些权益来自不同的部门内外的系统,甚至是跨公司合作。当然可以为每种不同的权益单独设计对应的模块提供服务,但是更合适的做法是:抽象出权益模型,使用权益类型区分,这样权益可以统一存储,打包权益的发放可以由DN事务天然的支持,并且可通过用户表示UID对用户权益分表;

此外,发放权益和查询用户权益这2个功能是每个权益类型服务都应该具备的,因此可以抽象成权益服务模板,让各个权益类型实现这个模板;当需要对接新权益或移除旧权益时,只需要调整实现类和权益类型枚举,而不需要修改主流程的代码逻辑。
在这里插入图片描述

架构设计

该设计的核心在于

  • 策略模式,实现了每一个特定权益的特性
  • 模板方法,把每一个权益的公共方法抽取出来。

代码示例

/**
 * 权益工厂
 */
@Service
public class BenefitServiceFactory {
 
    @Autowired
    private List<BenefitBaseTemplate> list;
 
    private static Map<Integer, BenefitBaseTemplate> typeServiceMap = Maps.newConcurrentMap();
 
    @PostConstruct
    public void init() {
         map = list.stream().collect(Collectors.toMap(BenefitBaseTemplate::getApprovalType, obj -> obj));
    }
 
    /**
     * 根据权益类型获取对应服务
     * @param benefitType
     * @return
     */
    public BenefitBaseTemplate getService(Integer benefitType) {
        return typeServiceMap.get(benefitType);
    }
 
}

策略执行,根据权益类型获取对应的权益发放服务,执行权益发送

	// 取出service
	BenefitBaseTemplate benefitService = benefitServiceFactory.getService(receiveBenefitReqDTO.getBenefitType());
	// 同步
	benefitService.syncSendBenefit(receiveBenefitReqDTO);

模板方法,所有的权益都是构造请求,入库,调用RPC发送请求。但是sendBenefit由子类实现。

@Slf4j
public abstract class BenefitBaseTemplate {
 
    /**
     * 同步发放权益
     */
    public ReceiveBenefitResp syncSendBenefit(ReceiveBenefitReqDTO receiveBenefitReqDTO){
        // 构造请求参数
        SendBenefitReq sendBenefitReq = buildSendBenefitReq(receiveBenefitReqDTO);
        // 请求数据先入库,失败直接返回
        reqDataIntoDB(sendBenefitReq);
        SendBenefitResp sendResult;
        try {
            // 入库成功再调用RPC发放权益
            sendResult = this.sendBenefit(sendBenefitReq);
            // 更新用户权益信息
            updateUserBenefitAfterSendSuc(sendResult);
        } catch (Exception e) {
            log.error("[benefit receive]syncSendBenefitByType_error_rollback! [receiveBenefitReqDTO={}]", JSON.toJSONString(receiveBenefitReqDTO));
            deleteReqDataInDB(sendBenefitReq);
            throw e;
        }
        return new ReceiveBenefitResp(sendResult);
    }
    
     /**
     * 发放权益
     *
     * @param sendBenefitReq
     * @return
     */
    public abstract SendBenefitResp sendBenefit(SendBenefitReq sendBenefitReq);
}

礼券服务

/**
 * 礼券服务
 */
@Slf4j
@Service("ticketService")
public class TicketServiceImpl extends BenefitBaseTemplate implements TicketService {
 
    @HystrixCommand(groupKey = "TicketServiceGroupKey", commandKey = "sendTicketCommandKey", fallbackMethod = "sendTicketFallback", ignoreExceptions = BusinessException.class)
    @Override
    public SendBenefitResp sendBenefit(SendBenefitReq sendTicketReq) {
        /*...*/
        ResponseInfo<List<SaveTicketVO>> facadeResult;
        try {
            facadeResult = platformUserTicketFacade.sendUserTickets(param);
        } catch (Throwable e) {
            log.error("[SERIOUS_DUBBO]UserTicketFacade.sendUserTicket_error! [openid={} ticketId={} sendNo={}] e:{}",
                    sendTicketReq.getOpenid(), sendTicketReq.getBenefitId(), sendTicketReq.getSendNo(), e);
            throw new RuntimeException();
        }
    }
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值