我是靠谱客的博主 整齐小馒头,最近开发中收集的这篇文章主要介绍模板模式+策略模式优化,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

写在最前面,最近在项目中发现一部分代码,可以用模板模式+策略模式来进行优化。

背景

业务中,系统中对订单状态的处理,需要发送对用户短信发送或者微信推送等操作。

发送短信和微信推送钱,需要处理逻辑,比如获取模板,可能还有查询逻辑,或者一些扩展字段逻辑处理等
在发送和推送之后,可能需要记录日志等,有可能不需要。

在优化之前我们的代码是这样

//这里写伪代码
// -----  业务代码
// 创单单未支付

1 发送短信,
2 发送推送
3 记录日志

///  业务 代码
//创单成功

1 发送短信,
2 发送推送
3 记录日志

//支付成功 等等

//取消  等等
1 发送短信,
2 发送推送
3 记录日志


这样的 代码很多,对此如取消订单入口很多,比如后台客服取消,客户端 客户取消,还有超时取消,供应商取消等。

那我们每个地方都写一遍上述代码,发短信,推送?

显然是可以的,但存在以前几个问题

1 这样代码重复率很高
2 非异步执行(请求很多会影响吞吐量)
3 多处修改

优化

方案 1

将发送短信,推送短信全部剥离抽取到一个方法里,在调用的地方全部调用一下。


class Utile{

static void doSend(){
//伪代码

if(创单未支付){
//业务代码
}else if(取消){
//业务代码
}
// 其他状态省略

}

}


调用地方


Utile.doSend()

但是这样还是同步,每个地方还是会用重复,还是会有同步调用问题,同样业务量大的时候还是会影响吞吐量。

方案 2 (增加异步线程发送 )

增加异步线程发送


class Utile{


    private static final AtomicInteger atomicInteger = new AtomicInteger();

    public static final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(500), (r) -> {
        Thread thread = new Thread(r);
        thread.setName("ExecutorUtil-pool-send-push" + atomicInteger.getAndIncrement());
        thread.setUncaughtExceptionHandler((t, e) -> {
            loggerHelper.errorLog(t.getName() + " 线程处理异常 : " + e.getMessage(),new RuntimeException(e));
            e.printStackTrace();
        });
        return thread;
    }, new ThreadPoolExecutor.AbortPolicy());

static void doSend(int orderType){

//这里使用线程池


   executor.execute(()->{
            //伪代码

		if(创单未支付){
		//业务代码
		}else if(取消){
		//业务代码
		}
		// 其他状态省略          
});


}


使用线程池也存在几个问题

  • 1 首先线程数量选择多少 线程数量占用多也不好,会影响业务线程
  • 2 队列容量多大?
  • 3 队列满了 怎么办?
  • 4 发送失败怎么办,发短信和推送也不是很重要的业务,可以忽略

业务量少的时候,这种解决办法也是可以的。但不太适合大的业务量。

方案 2 (mq + 设计模式 处理 )

这里我们不关心mq的处理,前提是已经放入mq 这里我们直接默认从mq拿。

重点是设计模式,设计的思想。

基于上面公用类 Utile ,处理和发送短信和 消息

如果后期随着业务量的增加或者推送方推送或者发送短信,对此,在公用类中进行添加if判断进行处理?
业务中如果发送和推送也需要记录日志,不同的方式记录不同的日志?

原方法


// 代码进行了 部分伪代码处理
    public void mqSendWXMessage(WxOrderNoBean wxOrderNoBean) {

        // -----------------  -  微信推送 -----------------------
        if (wxOrderNoBean.getType() == WxPushTypeEnum.COMPLETE_CHECK_TICKET.getValue()) {
           // 业务逻辑......
            
            //微信推送
            orderDetailInfoList.forEach(detailInfo -> wechatTemplateSettingService.wechatMessageForCompleteCheck(detailInfo));
            return;
        }else if (wxOrderNoBean.getType() == WxPushTypeEnum.CANCEL_to_supplier.getValue()){
            // 业务逻辑......
                    loggerHelper.infoLog("工作人员列表:" + JSON.toJSONString(stewardList), wxOrderNoBean.getOrderNo());
                    //微信推送 工作人员
                    WechatMessageUtil.cancelOrderInfoToSupplier(stewardList, validOrderInfoList.get(0));
                
                return;
           
        }
        
        List<RideOrderInfo> validOrderInfoList = rideOrderInfoDao.findByOrderNos("", Arrays.asList(wxOrderNoBean.getOrderNo()));
        List<RideOrderInfo> wxOrderInfoList = validOrderInfoList.stream().filter(item -> (item.getStoreId() == null || item.getStoreId() == 0)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(wxOrderInfoList)) {
            return;
        }
        RideOrderInfo rideOrderInfo = wxOrderInfoList.get(0);
        WechatPaySetting paySetting = wechatPaySettingDao.findByVcode(rideOrderInfo.getVcode());
        WechatTemplateSetting templateSetting= null;
        int logSataus = 0;
        int logType = 0;
        String remark = "";

        if (wxOrderNoBean.getType() == WxPushTypeEnum.USER_CANCEL.getValue()){  //用户取消
            // 业务逻辑......
            WechatMessageUtil.cancelOrderToCustomer(rideOrderInfo, paySetting, templateSetting, refundFee, chargeFee);
            remark = "用户取消订单推送";
            logType =  OrderLogStatus.REFUND_USER.getValue();

            // 商家取消
        }else if (wxOrderNoBean.getType() == WxPushTypeEnum.SUPPLIER_CANCEL.getValue()){
            // 业务逻辑......
           
            WechatMessageUtil.ticketFailOrderToCustomer(rideOrderInfo, paySetting, templateSetting);
            remark = "商家取消订单推送";
            logType =  OrderLogOptType.NOT_SERVICE_OPT.getValue();
            logSataus =  OrderLogStatus.CANCELED_SUPPLY.getValue();
            // 非客服操作 出票成功
        }else if(wxOrderNoBean.getType() == WxPushTypeEnum.TICKET_OUT.getValue()){
            // 业务逻辑......
            //判断是否派车
            if (driverChangedMap!=null && driverChangedMap.get(rideOrderInfo.getOrderNo())) {
                logType = OrderLogStatus.SENTED.getValue();
            } else {
                logType = OrderLogStatus.CONFIRMED.getValue();
            }

            List<OrderPassenger> orderPassengerList = orderPassengerDao.getOrderPassengers(rideOrderInfo.getOrderNo());
            WechatMessageUtil.addOrderToCustomer(rideOrderInfo, paySetting, templateSetting, orderPassengerList);
            remark = "订单出票成功推送";
            logSataus = OrderLogStatus.REBOOK_SUCCESS.getValue();

            //非客服 改签推送
        }else if(wxOrderNoBean.getType() == WxPushTypeEnum.ORDER_REBOOK_SUCCESS.getValue()){
            // 业务逻辑......
           
            
            List<OrderPassenger> orderPassengerList = orderPassengerDao.getOrderPassengers(rideOrderInfo.getOrderNo());
            WechatMessageUtil.rebookOrderToCustomer(rideOrderInfo, orderPassengerList, oldShiftSchedule, paySetting, templateSetting);

            logSataus = OrderLogStatus.REBOOK_SUCCESS.getValue();
            remark = "改签订单推送";
            logType = OrderLogOptType.NOT_SERVICE_OPT.getValue();
        }else {
            return;
        }

        //记录日志
        rideOrderLogService.wxLogSave(new RideOrderLog(rideOrderInfo.getVcode(), rideOrderInfo.getOrderNo(),logSataus , remark, logType,
                rideOrderInfo.getTelephone(), Constants.PushChannel.WECHAT_CHANNEL, Constants.PushType.SYSTEM_PUSH, "SYSTEM"));

那这个方法随着改动会越来越混乱,对此,这里我们可以使用模板模式 + 策略模式来进行处理。

设计思想

首先,对具体方法进行抽象。

消息处理接口

public interface Message {

    void  dealMqMessage(WxOrderNoBean wxOrderNoBean);

}

不管是发送还是推送,可以分为事前操作, 发送or推送,事后操作,具体的操作让子类去实现。
以及类型区分也让子类去实现

抽象出来类

public abstract class AbstractDealMessage implements Message {

    @Override
    public void dealMqMessage(WxOrderNoBean wxOrderNoBean) {
        befor(wxOrderNoBean);
        doDeal(wxOrderNoBean);
        after(wxOrderNoBean);
    }


    public abstract void befor(WxOrderNoBean wxOrderNoBean);

    public abstract void doDeal(WxOrderNoBean wxOrderNoBean);

    public abstract void after(WxOrderNoBean wxOrderNoBean);



    public abstract int getType();

    public abstract   Class<?>  getClasz();
}

公共的逻辑处理实现

公共类里可以增加,日志类型,日志状态,日志备注,一些模板业务查询 bean ,是否需要处理下一步的 flag

这里将一些公共的行为,do操作,操作前,操作后让父类(也就是当前类)实现,差异以及类型让子类去实现。



public abstract class AbstractDealWxMqMessage extends AbstractDealMessage {

    private LoggerHelper loggerHelper = LoggerHelper.getLoggerHelper(xxxxxxxx, AbstractDealWxMqMessage.class.getSimpleName());

//订单查询
    private RideOrderInfoDao rideOrderInfoDao;

//日志记录bean
    private RideOrderLogService rideOrderLogService;

    private WechatPaySettingDao wechatPaySettingDao;

//模板查询
    private WechatTemplateSettingService wechatTemplateSettingService;

//模板查询
    private WechatTemplateSetting  templateSetting;

//订单
    private RideOrderInfo rideOrderInfo;

//微信模板
    private WechatPaySetting paySetting;

// 日志 备注
    private String remark;

//日志类型
    private int logType;

// 日志状态
    private int logSataus;

    //是否继续执行
    private boolean isDo;

    public void setDo(boolean aDo) {
        isDo = aDo;
    }

    public RideOrderInfo getRideOrderInfo() {
        return rideOrderInfo;
    }

    public WechatPaySetting getPaySetting() {
        return paySetting;
    }

    public WechatTemplateSetting getTemplateSetting() {
        return templateSetting;
    }


    public void setRemark(String remark) {
        this.remark = remark;
    }

    public void setLogType(int logType) {
        this.logType = logType;
    }

    public void setLogSataus(int logSataus) {
        this.logSataus = logSataus;
    }

    public AbstractDealWxMqMessage(RideOrderLogService rideOrderLogService, WechatPaySettingDao wechatPaySettingDao,
                                   WechatTemplateSettingService wechatTemplateSettingService
            , RideOrderInfoDao rideOrderInfoDao) {
        this.rideOrderLogService = rideOrderLogService;
        this.wechatPaySettingDao = wechatPaySettingDao;
        this.wechatTemplateSettingService = wechatTemplateSettingService;
        this.rideOrderInfoDao = rideOrderInfoDao;
        this.isDo = true;
    }


    @Override
    public void befor(WxOrderNoBean wxOrderNoBean) {

        List<RideOrderInfo> validOrderInfoList = rideOrderInfoDao.findByOrderNos("", Arrays.asList(wxOrderNoBean.getOrderNo()));
        if (CollectionUtils.isEmpty(validOrderInfoList)) {
            isDo = false;
            return;
        }

        rideOrderInfo = validOrderInfoList.get(0);
        paySetting = wechatPaySettingDao.findByVcode(rideOrderInfo.getVcode());

    }


    public boolean findTemplateSetting(int templateType) {
        if (!isDo) {
            return false;
        }

        templateSetting = wechatTemplateSettingService.findActiveByTemplateType(rideOrderInfo.getVcode(), templateType);
        if (null == templateSetting) {
            loggerHelper.infoLog(" 暂无微信推送模板信息 ");
            isDo = false;
            return false;
        }

        return true;
    }

    @Override
    public void after(WxOrderNoBean wxOrderNoBean) {

//是否需要记录日志 判断
        if (!isDo) {
            return;
        }

        rideOrderLogService.wxLogSave(
                new RideOrderLog(
                        rideOrderInfo.getVcode(),
                        rideOrderInfo.getOrderNo(),
                        logSataus,
                        remark,
                        logType,
                        rideOrderInfo.getTelephone(),
                        Constants.PushChannel.WECHAT_CHANNEL,
                        Constants.PushType.SYSTEM_PUSH,
                        "SYSTEM")
        );
    }



}

最后不同的业务类实现,这里我们列出一个即可,其他的大体相同

比如说取消推送


/**
 * 用户取消 USER_CANCEL
 */
@Component
@Scope("prototype")  //这里为了防止线程安全,我们这里使用多例。 当然自己也可以去其他方法处理
public class UserCancelMqMessage extends AbstractDealWxMqMessage {


//注入 需要的对象bean
    @Autowired
    public UserCancelMqMessage(RideOrderLogService rideOrderLogService, WechatPaySettingDao wechatPaySettingDao, WechatTemplateSettingService wechatTemplateSettingService, RideOrderInfoDao rideOrderInfoDao) {
        super(rideOrderLogService,wechatPaySettingDao,wechatTemplateSettingService, rideOrderInfoDao);
    }


//真的差异处理, 处理一些差异(扩展)字段,是否需要执行下一步记录日志等  ,这里在上面父类中将推送的模板信息已经查了
    @Override
    public void doDeal(WxOrderNoBean wxOrderNoBean) {

//调用父类 查询模板
        if (!super.findTemplateSetting(TemplateTypeEnum.USER_CANCEL.getValue())) {
            return;
        }

        RideOrderInfo rideOrderInfo = super.getRideOrderInfo();
        WechatPaySetting paySetting = super.getPaySetting();
        WechatTemplateSetting templateSetting = super.getTemplateSetting();

        Map<String, String> map = JSON.parseObject(wxOrderNoBean.getExtensionField(), Map.class);
        String refundFee = map.get("refundFee");
        String chargeFee = map.get("chargeFee");

        WechatMessageUtil.cancelOrderToCustomer(rideOrderInfo, paySetting, templateSetting, refundFee, chargeFee);

//设置类型  属性  备注
        super.setRemark("用户取消订单推送");
        super.setLogType(OrderLogOptType.NOT_SERVICE_OPT.getValue());
        super.setLogSataus(OrderLogStatus.REFUND_USER.getValue());

    }

    @Override
    public int getType() {
        return WxPushTypeEnum.USER_CANCEL.getValue();
    }
    @Override
    public Class<?> getClasz() {
        return UserCancelMqMessage.class;
    }
}

供应商取消提醒

@Component
@Scope("prototype")
public class CancelToSupplierMqMessage extends AbstractDealWxMqMessage {


    private RideOrderInfoDao rideOrderInfoDao;

    //private WechatTemplateSettingService wechatTemplateSettingService;


//这里额外查询逻辑  
    @Autowired
    private StewardInfoService stewardInfoService;

//注入
    @Autowired
    public CancelToSupplierMqMessage(RideOrderLogService rideOrderLogService, WechatPaySettingDao wechatPaySettingDao, WechatTemplateSettingService wechatTemplateSettingService, RideOrderInfoDao rideOrderInfoDao) {
        super(rideOrderLogService, wechatPaySettingDao, wechatTemplateSettingService, rideOrderInfoDao);
        this.rideOrderInfoDao = rideOrderInfoDao;
        //this.wechatTemplateSettingService = wechatTemplateSettingService;
    }

//这个里处理 不需要事前逻辑 不做任何处理
    @Override
    public void befor(WxOrderNoBean wxOrderNoBean) {
        //this class not do any req
        return;
    }


//逻辑处理
    @Override
    public void doDeal(WxOrderNoBean wxOrderNoBean) {
//
//        if (!super.findTemplateSetting(WxPushTypeEnum.CANCEL_to_supplier.getValue())) {
//            super.setDo(false);
//            return;
//        }

// 同理 获取扩展字段
        Map<String, Object> map = JSON.parseObject(wxOrderNoBean.getExtensionField(), Map.class);
        if (map == null) {
            return;
        }

//查询
        RideOrderInfo validOrderInfoList = rideOrderInfoDao.findByOrderNos("", wxOrderNoBean.getOrderNo());
        if (CollectionUtils.isNotEmpty(validOrderInfoList)) {
            // 逻辑省略 
            WechatMessageUtil.cancelOrderInfoToSupplier(stewardList, validOrderInfoList.get(0));
        }

        //not log  不需要记录日志 等下一步 操作
        // or
        // Override after method
        super.setDo(false);

    }

    @Override
    public int getType() {
        return WxPushTypeEnum.CANCEL_to_supplier.getValue();
    }
  @Override
    public Class<?> getClasz() {
        return CancelToSupplierMqMessage.class;
    }
}

最后调用很简单


	//单例里注入多例 还是单例 对象
    @Autowired
    private List<AbstractDealWxMqMessage> abstractDealWxMqMessage;

		  int type = wxOrderNoBean.getType();
        loggerHelper.infoLog("消费监听消息: mqSendWXMessage " + JSON.toJSONString(wxOrderNoBean));
        Optional<AbstractDealWxMqMessage> first = abstractDealWxMqMessage.stream().filter(x -> x.getType() == type).findFirst();
        if (!first.isPresent()) {
            return;
        }
        // 单例里注入多例 还是单例 对象    
        // 这里是保证线程安全  使用多例 每次从容器获取
        Class<?> classz = first.get().getClasz();
        AbstractDealWxMqMessage beanByClass = (AbstractDealWxMqMessage) SpringContextUtils.getBeanByClass(classz);
        beanByClass.dealMqMessage(wxOrderNoBean);

mq 类型bean WxOrderNoBean

public class WxOrderNoBean {
   private String orderNo;
    /**
     * 1 订单改派
     * 2 出票成功(确认并且填入司机信息)订单改派
     */
    private int type;
    /**
     * 扩展字段  这里我们传json 了 
     */
    private String extensionField;

    public WxOrderNoBean() {
    }

    public WxOrderNoBean(String orderNo, int type) {
        this.orderNo = orderNo;
        this.type = type;
    }

    public WxOrderNoBean(String orderNo, int type, String extensionField) {
        this.orderNo = orderNo;
        this.type = type;
        this.extensionField = extensionField;
    }

  //get  set 省略


}

最后类图奉上

在这里插入图片描述

这样看是不是很清晰,也很好扩展。

最后

以上就是整齐小馒头为你收集整理的模板模式+策略模式优化的全部内容,希望文章能够帮你解决模板模式+策略模式优化所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部