项目中的《访问者模式》

这个模式核心思想是将基本的数据对象和对应的操作相互分离。数据对象就只是数据对象,如果想要扩展操作,就扩展对应的visitor。

这种模式下的两次分派

第一次分派,是将对数据对象本身进行分派,可以有不同的实现。
第二次分派,是visitor接收不同的数据对象。
结果就是数据对象接受了visitor,然后visitor中组合了数据对象。

这个项目中的使用场景

对于订单状态,有两个数据载体,一个是数据库已存在的当前的状态,一个是消息推送过来的状态。通过两个载体的状态的组合,能做出响应的动作。
处理逻辑如下⬇︎⬇︎⬇︎
image

UML是这样的⬇︎⬇︎⬇︎
image

实际代码是这样的⬇︎⬇︎⬇︎

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;
    }
}

复杂的状态对应关系就这样解决了。

posted @ 2024-12-17 21:50  Eular  阅读(21)  评论(0编辑  收藏  举报