订单状态流转之状态模式编码

3,908 阅读4分钟

背景

在某个项目中,用户有下单的功能,并且,在不同的状态下是有不同的事件去进行不同的处理和订单状态的流转。如果只是单纯的使用if else 来进行编码,代码可读性、扩展性、维护性将会变得很差,所以这里使用了状态模式进行编码和设计。

订单状态的流转情况

image.png

分析需要类和接口

首先,明确一个概念,因为不同的订单状态可能会有不同的操作,我们称这些订单操作叫做订单事件,所以我们需要一个订单事件接口。接着,不同的订单状态对应不同的处理,所以我们需要订单的抽象类和具体的订单实现类。同一个事件处理是相同的,我们可以将处理的事情放到同一个处理器去处理,便于维护。还包括一些context上下文,为了方便参数的扩展和上文内容的传递。 总结我们需要有大概一下类和接口

  • 订单事件接口
  • 抽象状态类
  • 不同状态具体实现类
  • context上下文
  • 具体事件的处理类
  • service的调用

具体代码实现

状态抽象类

/**
 * @author: zyb
 */
public class AbstractOrderStatus implements OrderEvent {

    @Override
    public void orderTimeout(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void paySuccess(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void startServe(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void serverTimeEnd(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void serverExpire(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void autoFinishOrder(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void approveRefund(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void refuseRefund(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void canceledOrder(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void comment(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }

    @Override
    public void autoComment(OrderStatusContext context) {
        throw new ServiceErrorException("目前订单状态不支持该流转");
    }
}

具体的状态

这里简单列出两个状态具体实现类

服务中状态

/**
 * @author: zyb
 */
@Component("IN_SERVICE")
public class InServiceStatus extends AbstractOrderStatus {

    @Autowired
    private OrderEventHandel orderEventHandel;

    @Override
    public void serverTimeEnd(OrderStatusContext context) {
        orderEventHandel.serverTimeEnd(context);
    }

    @Override
    public void serverExpire(OrderStatusContext context) {
        orderEventHandel.serverExpire(context);
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        orderEventHandel.finishOrder(context);
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        orderEventHandel.applyRefund(context);
    }
}

待支付状态

/**
 * @author: zyb
 */
@Component("WAIT_SERVICE")
public class WaitServiceStatus extends AbstractOrderStatus {

    @Autowired
    private OrderEventHandel orderEventHandel;

    @Override
    public void startServe(OrderStatusContext context) {
        orderEventHandel.startServe(context);
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        orderEventHandel.finishOrder(context);
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        orderEventHandel.applyRefund(context);
    }
}

订单事件接口

/**
 * @author: zyb
 */
public interface OrderEvent {


    /**
     * 订单超时
     */
    void orderTimeout(OrderStatusContext context);

    /**
     * 支付成功
     */
    void paySuccess(OrderStatusContext context);

    /**
     * 开始服务
     */
    void startServe(OrderStatusContext context);

    /**
     * 服务时间结束
     */
    void serverTimeEnd(OrderStatusContext context);

    /**
     * 服务过期
     */
    void serverExpire(OrderStatusContext context);

    /**
     * 完成订单
     */
    void finishOrder(OrderStatusContext context);

    /**
     * 自动完成订单
     */
    void autoFinishOrder(OrderStatusContext context);

    /**
     * 申请退款
     */
    void applyRefund(OrderStatusContext context);

    /**
     * 同意退款
     */
    void approveRefund(OrderStatusContext context);

    /**
     * 拒绝退款
     */
    void refuseRefund(OrderStatusContext context);

    /**
     * 取消订单
     */
    void canceledOrder(OrderStatusContext context);

    /**
     * 评价
     */
    void comment(OrderStatusContext context);

    /**
     * 自动评价
     */
    void autoComment(OrderStatusContext context);
}

事件处理Handler

/**
 * @author: zyb
 */
@Component
@Transactional
public class OrderEventHandel implements OrderEvent {

    @Override
    public void orderTimeout(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void paySuccess(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void startServe(OrderStatusContext context) {
       // TODO: 具体处理逻辑
    }

    @Override
    public void serverTimeEnd(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void serverExpire(OrderStatusContext context) {
       // TODO: 具体处理逻辑
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void autoFinishOrder(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void approveRefund(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void refuseRefund(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void canceledOrder(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void comment(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }

    @Override
    public void autoComment(OrderStatusContext context) {
        // TODO: 具体处理逻辑
    }
    
}

context

/**
 * @author: zyb
 */
@Data
public class OrderStatusContext {

    private AbstractOrderStatus orderStatus;
    private String orderEvent;
    private Long orderId;
    private OrderEventParam orderEventParam;

    public OrderStatusContext(AbstractOrderStatus orderStatus,
                              String orderEvent,
                              Long orderId,
                              OrderEventParam orderEventParam) {
        this.orderStatus = orderStatus;
        this.orderEvent = orderEvent;
        this.orderId = orderId;
        this.orderEventParam = orderEventParam;
    }

    public Boolean doAction() {
        switch (orderEvent) {
            case OrderConstant.APPLY_REFUND:
                orderStatus.applyRefund(this);
                break;
            case OrderConstant.APPROVE_REFUND:
                orderStatus.approveRefund(this);
                break;
            case OrderConstant.CANCELED_ORDER:
                orderStatus.canceledOrder(this);
                break;
            case OrderConstant.FINISH_ORDER:
                orderStatus.finishOrder(this);
                break;
            case OrderConstant.AUTO_FINISH_ORDER:
                orderStatus.autoFinishOrder(this);
                break;
            case OrderConstant.ORDER_TIMEOUT:
                orderStatus.orderTimeout(this);
                break;
            case OrderConstant.PAY_SUCCESS:
                orderStatus.paySuccess(this);
                break;
            case OrderConstant.REFUSE_REFUND:
                orderStatus.refuseRefund(this);
                break;
            case OrderConstant.SERVER_TIME_EDN:
                orderStatus.serverTimeEnd(this);
                break;
            case OrderConstant.START_SERVE:
                orderStatus.startServe(this);
                break;
            case OrderConstant.COMMENT:
                orderStatus.comment(this);
                break;
            case OrderConstant.AUTO_COMMENT:
                orderStatus.autoComment(this);
                break;
            default:
                throw new ServiceErrorException("暂不支持此事件");
        }
        return true;
    }
}

service层调用

public boolean orderEvent(Long id, String orderEvent, OrderEventParam orderEventParam) {
        OrderInfoEntity orderInfoEntity = orderInfoMapper.selectById(id);
        AbstractOrderStatus orderStatus = (AbstractOrderStatus) SpringContextUtils.getBean(orderInfoEntity.getOrderStatus());
        OrderStatusContext context = new OrderStatusContext(orderStatus, orderEvent, id, orderEventParam);
        context.doAction();
        return true;
}

其他实现方式

在Spring框架项目中,开发者可以通过简单的配置就能获得一个业务状态机,而不需要自己去管理状态机的定义、初始化等过程。有兴趣的同学也可以去学习一下。

总结

在复杂的业务场景下,合理的使用设计模式,能很大程度使我们的代码维护性、可读性、扩展性更好。 有错误可以指出,欢迎讨论。