项目中的《访问者模式》
这个模式核心思想是将基本的数据对象和对应的操作相互分离。数据对象就只是数据对象,如果想要扩展操作,就扩展对应的visitor。
这种模式下的两次分派
第一次分派,是将对数据对象本身进行分派,可以有不同的实现。
第二次分派,是visitor接收不同的数据对象。
结果就是数据对象接受了visitor,然后visitor中组合了数据对象。
这个项目中的使用场景
对于订单状态,有两个数据载体,一个是数据库已存在的当前的状态,一个是消息推送过来的状态。通过两个载体的状态的组合,能做出响应的动作。
处理逻辑如下⬇︎⬇︎⬇︎
UML是这样的⬇︎⬇︎⬇︎
实际代码是这样的⬇︎⬇︎⬇︎
DbStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.BusinessStatusEnum;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* @author Euler
*/
public abstract class DbStatus {
/**
* 处理结果
*/
private Integer businessStatus;
public DbStatus(Integer businessStatus) {
this.businessStatus = businessStatus;
}
private DbStatus() {
}
/**
* 接收天猫状态的visitor
* @param tmallVisitorStatus
* @return
*/
public abstract MessageDealWithResultEnum acceptTmallVisitor(TmallVisitorStatus tmallVisitorStatus);
/**
* 将DB记录的处理结果转成BusinessStatusEnum
* @return
*/
protected BusinessStatusEnum getBusinessStatus(){
return BusinessStatusEnum.valueOfCode(businessStatus);
}
}
DbPayedStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* db记录已支付
* @author Euler
*/
public class DbPayedStatus extends DbStatus{
public DbPayedStatus(Integer businessStatus) {
super(businessStatus);
}
/**
* 接收天猫状态的visitor
*
* @param tmallVisitorStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum acceptTmallVisitor(TmallVisitorStatus tmallVisitorStatus) {
return tmallVisitorStatus.visitDbStatus(this);
}
}
DbCloseStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* db记录已关闭
* @author Euler
*/
public class DbCloseStatus extends DbStatus{
public DbCloseStatus(Integer businessStatus) {
super(businessStatus);
}
/**
* 接收天猫状态的visitor
*
* @param tmallVisitorStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum acceptTmallVisitor(TmallVisitorStatus tmallVisitorStatus) {
return tmallVisitorStatus.visitDbStatus(this);
}
}
DbChargeOffStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* db记录已核销
* @author Euler
*/
public class DbChargeOffStatus extends DbStatus{
public DbChargeOffStatus(Integer businessStatus) {
super(businessStatus);
}
/**
* 接收天猫状态的visitor
*
* @param tmallVisitorStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum acceptTmallVisitor(TmallVisitorStatus tmallVisitorStatus) {
return tmallVisitorStatus.visitDbStatus(this);
}
}
TmallVisitorStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.BusinessStatusEnum;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* 天猫visitor
*
* @author Euler
*/
public interface TmallVisitorStatus {
/**
* 判断数据库记录是否处理成功
*
* @param statusEnum
*
* @return
*/
default boolean dbRecordIsFail(BusinessStatusEnum statusEnum) {
return BusinessStatusEnum.ABNORMAL.equals(statusEnum) || BusinessStatusEnum.CREATE_ORDER_ABNORMAL.equals(statusEnum);
}
/**
* 访问Db 已支付状态
*
* @param dbPayedStatus
*
* @return
*/
MessageDealWithResultEnum visitDbStatus(DbPayedStatus dbPayedStatus);
/**
* 访问Db已核销状态
*
* @param dbChargeOffStatus
*
* @return
*/
MessageDealWithResultEnum visitDbStatus(DbChargeOffStatus dbChargeOffStatus);
/**
* 访问Db 已退款状态
*
* @param dbCloseStatus
*
* @return
*/
MessageDealWithResultEnum visitDbStatus(DbCloseStatus dbCloseStatus);
}
TmallVisitorPayedStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.BusinessStatusEnum;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* 天猫已支付状态
* @author Euler
* @date 2022 2022/11/22
*/
public class TmallVisitorPayedStatus implements TmallVisitorStatus {
/**
* 访问Db 已支付状态
*
* @param dbPayedStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbPayedStatus dbPayedStatus) {
BusinessStatusEnum businessStatus = dbPayedStatus.getBusinessStatus();
// 支付处理失败重试
if (dbRecordIsFail(businessStatus)) {
return MessageDealWithResultEnum.NORMAL;
// 支付处理成功,又来支付成功消息,视为重复消息,清除
}else{
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
}
/**
* 访问Db已核销状态
*
* @param dbChargeOffStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbChargeOffStatus dbChargeOffStatus) {
// 状态已经走到核销,又来已支付的消息。视为延时重复消息,清除
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
/**
* 访问Db 已退款状态
*
* @param dbCloseStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbCloseStatus dbCloseStatus) {
// 状态已走到关闭,又来已支付消息,视为延时消息,清除
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
}
TmallVisitorCloseStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
*
* 天猫已退款状态
* @author Euler
*/
public class TmallVisitorCloseStatus implements TmallVisitorStatus{
/**
* 访问Db 已支付状态
*
* @param dbPayedStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbPayedStatus dbPayedStatus) {
boolean dbRecordIsFail = dbRecordIsFail(dbPayedStatus.getBusinessStatus());
// 已支付消息处理失败,订单没有创建成功,不能处理退款的消息
if (dbRecordIsFail) {
return MessageDealWithResultEnum.NO_SEQUENCE_MESSAGE;
// 已支付消息处理成功,可以正常处理退款消息
}else{
return MessageDealWithResultEnum.NORMAL;
}
}
/**
* 访问Db已核销状态
*
* @param dbChargeOffStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbChargeOffStatus dbChargeOffStatus) {
// 已核销和已退款是互斥消息,处理了核销,就不能处理退款。(天猫核销后不能在天猫退款)
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
/**
* 访问Db 已退款状态
*
* @param dbCloseStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbCloseStatus dbCloseStatus) {
boolean dbRecordIsFail = dbRecordIsFail(dbCloseStatus.getBusinessStatus());
// 退款消息处理失败,再来退款重试消息,正常处理
if (dbRecordIsFail) {
return MessageDealWithResultEnum.NORMAL;
// 退款消息处理成功了,再来退款消息,视为延时重复消息,清除
}else {
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
}
}
TmallVisitorChargeOffVisitorStatus
package com.xxx.sales.saicorder.outerapp.tmall.message.visitor;
import com.xxx.sales.saicorder.outerapp.tmall.enums.MessageDealWithResultEnum;
/**
* 天猫核销完成状态
* @author Euler
*/
public class TmallVisitorChargeOffVisitorStatus implements TmallVisitorStatus {
/**
* 访问Db 已支付状态
*
* @param dbPayedStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbPayedStatus dbPayedStatus) {
boolean dbRecordIsFail = dbRecordIsFail(dbPayedStatus.getBusinessStatus());
// 已支付消息处理失败,订单没有创建成功,不能处理核销的消息。消息重回队列
if (dbRecordIsFail) {
return MessageDealWithResultEnum.NO_SEQUENCE_MESSAGE;
// 已支付处理成功,正常处理核销消息
}else{
return MessageDealWithResultEnum.NORMAL;
}
}
/**
* 访问Db已核销状态
*
* @param dbChargeOffStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbChargeOffStatus dbChargeOffStatus) {
boolean dbRecordIsFail = dbRecordIsFail(dbChargeOffStatus.getBusinessStatus());
// 核销处理失败,又来核销重试消息,正常处理
if (dbRecordIsFail) {
return MessageDealWithResultEnum.NORMAL;
// 核销处理成功,又来核销消息,视为重复消息,清除
}else{
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
}
/**
* 访问Db 已退款状态
*
* @param dbCloseStatus
*
* @return
*/
@Override
public MessageDealWithResultEnum visitDbStatus(DbCloseStatus dbCloseStatus) {
// 关闭后不在接收核销消息,清除
return MessageDealWithResultEnum.IS_REPEATED_MESSAGE;
}
}
复杂的状态对应关系就这样解决了。
本文来自博客园,作者:Eular,转载请注明原文链接:https://www.cnblogs.com/euler-blog/p/18613488