background

In a project, the user has the function of placing an order, and in different states there are different events to carry out different processing and order state flow. If we only use if else to code, the code readability, extensibility and maintainability will become very poor, so we use state mode to code and design.

The flow of order status

Analysis requires classes and interfaces

First, to clarify the concept, because different order states may have different operations, we call these order operations order events, so we need an order event interface. Then, different order states correspond to different processing, so we need an abstract class for the order and a concrete order implementation class. The same event processing is the same, we can deal with things in the same processor to deal with, easy maintenance. Some context contexts are also included to facilitate parameter extension and passing above. To sum up, we need to have an overview of classes and interfaces

  • Order event interface
  • Abstract state class
  • Different state concrete implementation classes
  • The context context
  • A concrete event handler class
  • The service call

Concrete code implementation

State abstraction class

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

    @Override
    public void orderTimeout(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void paySuccess(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void startServe(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void serverTimeEnd(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void serverExpire(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void autoFinishOrder(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void approveRefund(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void refuseRefund(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void canceledOrder(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void comment(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow");
    }

    @Override
    public void autoComment(OrderStatusContext context) {
        throw new ServiceErrorException("The current order status does not support this flow"); }}Copy the code

Concrete state

Two state concrete implementation classes are briefly listed here

In-service state

/ * * *@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); }}Copy the code

Pending payment status

/ * * *@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); }}Copy the code

Order event interface

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


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

    /** * Paid successfully */
    void paySuccess(OrderStatusContext context);

    /** * Start service */
    void startServe(OrderStatusContext context);

    /** * Service time ends */
    void serverTimeEnd(OrderStatusContext context);

    /** * Service expired */
    void serverExpire(OrderStatusContext context);

    /** * complete the order */
    void finishOrder(OrderStatusContext context);

    /** * Automatically complete the order */
    void autoFinishOrder(OrderStatusContext context);

    /** * Apply for a refund */
    void applyRefund(OrderStatusContext context);

    /** * Agree to refund */
    void approveRefund(OrderStatusContext context);

    /** * No refund */
    void refuseRefund(OrderStatusContext context);

    /** * Cancel the order */
    void canceledOrder(OrderStatusContext context);

    /** * evaluation */
    void comment(OrderStatusContext context);

    /** * automatic evaluation */
    void autoComment(OrderStatusContext context);
}

Copy the code

Event Handler

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

    @Override
    public void orderTimeout(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void paySuccess(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void startServe(OrderStatusContext context) {
       // TODO:Concrete processing logic
    }

    @Override
    public void serverTimeEnd(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void serverExpire(OrderStatusContext context) {
       // TODO:Concrete processing logic
    }

    @Override
    public void finishOrder(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void autoFinishOrder(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void applyRefund(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void approveRefund(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void refuseRefund(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void canceledOrder(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void comment(OrderStatusContext context) {
        // TODO:Concrete processing logic
    }

    @Override
    public void autoComment(OrderStatusContext context) {
        // TODO:Concrete processing logic}}Copy the code

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(a) {
        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("This event is not supported at this time");
        }
        return true; }}Copy the code

The service layer calls

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;
}
Copy the code

Other implementations

In Spring framework projects, developers can obtain a business state machine through simple configuration, without having to manage state machine definition, initialization, and so on. Interested students can also go to learn.

conclusion

In complex business scenarios, the rational use of design patterns can greatly improve the maintainability, readability and expansibility of our code. Any mistakes can be pointed out, welcome to discuss.