策略设计模式-下单
1、定义一个下单context类
通过这类来判断具体使用哪个实现类,可以通过一些枚举或者条件来判断
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、定义一个订单策略接口,并定义公用入参
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、定义不同类型下单策略实现类,根据业务可以有多个实现类
/**
* 疫苗订单逻辑
*
*/
@Slf4j
@Service
public class ConsultOrderStrategy implements OrderStrategy<OrderConfirmReq,OrderSubmitReq,YjkUserDetails> {
}