likes
comments
collection
share

一个简单的订单状态模式实现

作者站长头像
站长
· 阅读数 2

什么是状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为。在状态模式中,一个对象的行为取决于其当前状态,而且可以随时改变这个状态。状态模式将对象的状态封装在不同的状态类中,从而使代码更加清晰和易于维护。当一个对象的状态改变时,状态模式会自动更新该对象的行为,而不需要在代码中手动进行判断和处理。

在一般的订单模块中,订单状态是不可或缺的一个因素,订单状态因为业务需要的原因有多种实现,为了避免臃肿和混乱不清的代码结构,我们可以尝试将订单状态的变更抽象出来,单独做变更。

其中设计状态变更的前置代码,亦可在状态模式中处理,(比如订单从未支付到支付,需要去调用第三方支付接口或者其他实现,这个实现就可以在订单状态变更的内部实现。)

创建订单类,作为数据载体:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Order {

    // 状态类
    private OrderState orderState;

    // 订单号
    private String orderNo;

    // 订单状态
    private String status;
}

创建订单状态接口:如果不再细分的话,可以将订单所有涉及状态变更的操作都抽象成方法在这里列出来

public interface OrderState {

    // 提交订单
    OrderState submit();

    // 支付
    OrderState pay();

    // 取消
    OrderState cancel();

    // 再来一单
    OrderState reBuy();
    
    // 其他订单操作...
}

创建状态接口所有方法的默认处理方式(后面我们具体的订单状态类将继承此抽象类,在这里设置过默认处理后,我们的状态类也不需要实现全部的方法了)

@Data
@AllArgsConstructor
public abstract class AstractOrderState implements OrderState {

    // 我们要处理的数据
    private Order order;

    /**
    * 根据数据库的状态枚举获取状态类实例
    */
    public static OrderState getOrderStateByState(Order order) {
        switch (order.getStatus()) {
            case "NOSUBMIT":
                return new NotSubmitted(order);
            case "WAITPAY":
                return new WaitPay(order);
            default:
                throw new RuntimeException("状态未知" + order.getStatus());
        }
    }

    @Override
    public OrderState submit() {
        System.out.println("当前状态为:" + this.order.getStatus() + ",不支持提交操作");
        return this;
    }

    @Override
    public OrderState pay() {
        System.out.println("当前状态为:" + this.order.getStatus() + ",不支持付款操作");
        return this;
    }

    @Override
    public OrderState cancel() {
        System.out.println("当前状态为:" + this.order.getStatus() + ",不支持取消操作");
        return this;
    }

    @Override
    public OrderState reBuy() {
        System.out.println("当前状态为:" + this.order.getStatus() + ",不支持再来一单操作");
        return this;
    }
}

创建各个状态的对象,以及编写改对象的代码:

// 未提交状态
public class NotSubmitted extends AstractOrderState {

    public NotSubmitted(Order order) {
        super(order);
    }
    
    @Override
    public OrderState submit(){
        System.out.println("当前状态:" + this.getOrder().getStatus()+" 已提交");
        // 订单提交代码
        return new Submitted(this.getOrder());
    }

    @Override
    public OrderState cancel(){
        System.out.println("当前状态:" + this.getOrder().getStatus());
        // 订单提交代码
        return new Cancelled(this.getOrder());
    }
}
// 待支付状态
public class WaitPay extends AstractOrderState {

    public WaitPay(Order order) {
        super(order);
    }
    
    @Override
    public OrderState pay(){
        System.out.println("当前状态:" + this.getOrder().getStatus());
        // 支付代码
        return new Paid(this.getOrder());
    }
    
    @Override
    public OrderState cancel(){
        System.out.println("当前状态:" + this.getOrder().getStatus());
        // 订单提交代码
        return new Cancelled(this.getOrder());
    }
}
// 订单已完成状态
public class Done extends AstractOrderState {
    
    public Done(Order order) {
        super(order);
    }
    
    @Override
    public OrderState reBuy(){
        System.out.println("当前状态:" + this.getOrder().getStatus());
        // 再次购买代码
        return new NotSubmitted(this.getOrder());
    }
    
    @Override
    public OrderState cancel(){
        System.out.println("当前状态:" + this.getOrder().getStatus());
        // 订单提交代码
        return new Cancelled(this.getOrder());
    }
}

从代码中我们可以看出,不同的状态类只需要实现自己所能处理的方法即可,这样我们就将不同状态的职责划分给不同状态类了,这可以帮助我们更好的处理订单状态变更,当然这只是一个demo,想要使用订单状态模式去处理自己的需求还需要大家根据自己的工作需求去写不同的实现。归根到底这种设计模式只是将看似有共同点的不同处理划分成一类,然后再在此类中细分,如果我们有其他的类似需求也是可以用到上述设计模式的。

测试:

public class OrderController {
    public static void main(String[] args) {
        Order order = Order.builder()
                .status("NOSUBMIT")
                .build();
        order.setOrderState(AstractOrderState.getOrderStateByState(order));
        order.getOrderState().reBuy();
    }
}

这里我们创建一个未提交状态的订单,并且让他调用reBuy()方法,发现此状态没有实现reBuy()方法,代码就会走到我们的默认方法中,然后报错:

一个简单的订单状态模式实现

public class OrderController {
    public static void main(String[] args) {
        Order order = Order.builder()
                .status("NOSUBMIT")
                .build();
        order.setOrderState(AstractOrderState.getOrderStateByState(order));
        order.getOrderState().submit();
    }
}

当我们使用未提交状态去调用提交方法时,因为未提交状态类实现了此方法,就会走该实现,正常打印结果。

一个简单的订单状态模式实现