概述
前言
写在最前面,最近在项目中发现一部分代码,可以用模板模式+策略模式来进行优化。
背景
业务中,系统中对订单状态的处理,需要发送对用户短信发送或者微信推送等操作。
发送短信和微信推送钱,需要处理逻辑,比如获取模板,可能还有查询逻辑,或者一些扩展字段逻辑处理等
在发送和推送之后,可能需要记录日志等,有可能不需要。
在优化之前我们的代码是这样
//这里写伪代码
// ----- 业务代码
// 创单单未支付
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 省略
}
最后类图奉上
这样看是不是很清晰,也很好扩展。
最后
以上就是整齐小馒头为你收集整理的模板模式+策略模式优化的全部内容,希望文章能够帮你解决模板模式+策略模式优化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复