策略设计模式-下单

1、定义一个下单context类

通过这类来判断具体使用哪个实现类,可以通过一些枚举或者条件来判断

java 复制代码
import com.alibaba.fastjson.JSON;
import com.tc.common.exception.BusinessException;
import com.tc.common.user.YjkUserDetails;
import com.tc.institution.constant.RedisConstant;
import com.tc.institution.dto.req.order.OrderConfirmReq;
import com.tc.institution.dto.req.order.OrderSubmitReq;
import com.tc.institution.dto.resp.order.OrderConfirmResp;
import com.tc.institution.dto.resp.order.OrderSubmitResp;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO 4.0和4.1代码整合待完成
 * 1集中整合其他策略子类查询到OrderContext上下文,减少互相依赖
 * 2抽取已有共有方法到公共类
 *
 */
@Slf4j
@Service
public class OrderContext {

    @Autowired
    private List<OrderStrategy> orderStrategyList;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 增加策略请维护该注释!!!
     * req.buyDemandOrderId 不为空走BuyDemandOrderStrategy
     * req.bizType = CONSULTATION_FEE(6, "问诊费订单") && req.consultationOrderId 不为空走ConsultationFeeOrderStrategy
     *
     * @param req  请求参数
     * @param user 操作用户
     */
    public OrderConfirmResp confirm(OrderConfirmReq req, YjkUserDetails user) {
        log.info("Function confirm ,req={}", req);
        for (OrderStrategy orderStrategy : orderStrategyList) {
            if (orderStrategy.confirmSupport(req) && orderStrategy.confirmCheck(req)) {
                OrderConfirmResp confirmResp = orderStrategy.confirm(req, user);
                log.info("Function confirm ,resp={}", confirmResp);
                return confirmResp;
            }
        }
        throw new BusinessException("预下单方式异常");
    }

    /**
     * 增加策略请维护该注释!!!
     * req.buyDemandOrderId 不为空走BuyDemandOrderStrategy
     * req.bizType = CONSULTATION_FEE(6, "问诊费订单") && req.consultationOrderId 不为空走ConsultationFeeOrderStrategy
     * req.bizType = CONSULTATION_EXPERT(7, "专家问诊订单") && req.consultationOrderId 不为空走ConsultationFeeOrderStrategy
     *
     * @param req  请求参数
     * @param user 操作用户
     */
    public OrderSubmitResp submit(OrderSubmitReq req, YjkUserDetails user) {
        for (OrderStrategy orderStrategy : orderStrategyList) {
            if (orderStrategy.submitSupport(req) && orderStrategy.submitCheck(req)) {
                return getOrderSubmitResp(req, user, orderStrategy);
            }
        }
        throw new BusinessException("预下单方式异常");
    }

    private OrderSubmitResp getOrderSubmitResp(OrderSubmitReq req, YjkUserDetails user, OrderStrategy orderStrategy) {
        String submitLockKey = orderStrategy.getSubmitLockKey(req, user);
        RLock orderLock = redissonClient.getLock(RedisConstant.ORDER_SUBMIT_LOCK_KEY + submitLockKey);
        try {
            boolean orderLockFlag = orderLock.tryLock(-1, 1, TimeUnit.MINUTES);
            log.info("Function submit orderLockFlag:{} param:{}", orderLockFlag, JSON.toJSONString(req));
            if (orderLockFlag) {
                OrderSubmitResp orderSubmitResp = orderStrategy.submit(req, user);
                log.info("Function submit param:{} result:{}", JSON.toJSONString(req), JSON.toJSONString(orderSubmitResp));
                return orderSubmitResp;
            } else {
                log.info("Function submit get lock fail, key:{}, now exist ...", req.getBuyDemandOrderId());
                throw new BusinessException("订单处理中,请勿重复多次提交");
            }
        } catch (Exception e) {
            log.warn("Function submit getOrderLock fail:", e);
            throw new BusinessException(e.getMessage());
        } finally {
            if (orderLock.isLocked() && orderLock.isHeldByCurrentThread()) {
                orderLock.unlock();
            }
        }
    }
}

2、定义一个订单策略接口,并定义公用入参

java 复制代码
mport com.tc.institution.dto.req.order.OrderConfirmReq;
import com.tc.institution.dto.req.order.OrderSubmitReq;
import com.tc.institution.dto.resp.order.OrderConfirmResp;
import com.tc.institution.dto.resp.order.OrderSubmitResp;

/**
 * 下单通用策略
 */
public interface OrderStrategy<C,S,U> {

    /**
     * 预下单方式检验
     *
     * @param req 预下单请求参数
     * @return
     */
    boolean confirmSupport(OrderConfirmReq req);

    /**
     * 下单方式检验
     *
     * @param req 下单请求参数
     * @return
     */
    boolean submitSupport(OrderSubmitReq req);

    /**
     * 预下单参数校验
     *
     * @param req 预下单请求参数
     * @return
     */
    default boolean confirmCheck(OrderConfirmReq req) {
        return true;
    }

    /**
     * 下单参数校验
     *
     * @param req 下单请求参数
     */
    default boolean submitCheck(OrderSubmitReq req) {
        return true;
    }

    /**
     * 预下单
     *
     * @param req  预下单请求参数
     * @param user 用户数据
     * @return
     */
    OrderConfirmResp confirm(C req, U user);

    /**
     * 提交订单
     *
     * @param req  下单请求参数
     * @param user 用户数据
     * @return
     */
    OrderSubmitResp submit(S req, U user);

    /**
     * 获取提交订单锁
     *
     * @param req  下单请求参数
     * @param user 用户数据
     * @return
     */
    default String getSubmitLockKey(OrderSubmitReq req, U user) {
        return String.valueOf(req.getBuyDemandOrderId());
    }
}

3、定义不同类型下单策略实现类,根据业务可以有多个实现类

java 复制代码
/**
 * 疫苗订单逻辑
 *
 */
@Slf4j
@Service
public class ConsultOrderStrategy implements OrderStrategy<OrderConfirmReq,OrderSubmitReq,YjkUserDetails> {

}
相关推荐
侠客行03175 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪5 小时前
深入浅出LangChain4J
java·langchain·llm
子兮曰5 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
吴仰晖5 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神5 小时前
github发布pages的几种状态记录
前端
老毛肚7 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎7 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
不像程序员的程序媛8 小时前
Nginx日志切分
服务器·前端·nginx
Yvonne爱编码8 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚8 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言