LXX的网络日志
人因梦想而伟大
聊聊状态模式

介绍

状态模式(State Pattern),允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

它的用途,可以用来根据状态来支持相对应的操作。举个例子,比如,一个非常简单的订单(不涉及支付)场景。

它有三种状态:

  • 待接单(当用户下单后,就通知服务人员接单)
  • 进行中(当服务人员接单后,该订单显示进行中)
  • 已完成(订单完成后,服务人员手动关闭订单,该订单就完成了)

示例

好了,我们直接根据上面定义的状态来写一个示例:

// 服务订单类
public class ServiceOrder {
    /**
     * 待接单状态
     */
    final int WAITING = 0;
    /**
     * 进行中状态
     */
    final int ONGOING = 1;
    /**
     * 已完成状态
     */
    final int COMPLETED = 2;
    private final String order;
    /**
     * 默认待接单状态
     */
    int state = WAITING;

    public ServiceOrder(String order) {
        this.order = order;
        print();
    }

    public void serviceReceiving(String order) {
        System.out.println("服务人员已接单:" + order);
        state = ONGOING;
        print();
    }

    public void completedOrder(String order) {
        System.out.println("服务人员已完成该订单:" + order);
        state = COMPLETED;
        print();
    }


    public void print() {
        System.out.println("正在查询订单状态:");
        if (state == WAITING) {
            System.out.println("接收到新的订单:" + order);
            System.out.println("正在通知服务人员接单!");
            serviceReceiving(order);
        } else if (state == ONGOING) {
            System.out.println("订单进行中!");
        } else if (state == COMPLETED) {
            System.out.println("订单已完成!");
        }
    }
}

然后,再写个测试用例测试一下:

public static void main(String[] args) throws InterruptedException {
    String order = "\n====\n服务:远程修BUG\n价格:500¥\n====\n";
    ServiceOrder serviceOrder = new ServiceOrder(order);
    // 服务人员已完成订单
    serviceOrder.completedOrder(order);
}

输出结果如下:

正在查询订单状态:
接收到新的订单:
====
服务:远程修BUG
价格:500¥
====

正在通知服务人员接单!
服务人员已接单:
====
服务:远程修BUG
价格:500¥
====

正在查询订单状态:
订单进行中!
服务人员已完成该订单:
====
服务:远程修BUG
价格:500¥
====

正在查询订单状态:
订单已完成!

这个就是一个订单状态更变时的一个例子。不过代码中的IF ELSE 不是很好维护,缺乏灵活性。

不过,我们可以用状态模式来改进它。

// 状态接口
public interface OrderState {
    void serviceReceiving(String order);

    void completedOrder(String order);

    void print();
}
// 待接单
public class WaitingState implements OrderState {
    private final ServiceOrder serviceOrder;

    public WaitingState(ServiceOrder serviceOrder) {
        this.serviceOrder = serviceOrder;
    }

    @Override
    public void serviceReceiving(String order) {
        System.out.println("服务人员已接单:" + order);
        // 扭转状态
        serviceOrder.setState(serviceOrder.getOngoingState());
    }

    @Override
    public void completedOrder(String order) {
        System.out.println("该状态不支持当前操作!");
    }

    @Override
    public void print() {
        System.out.println("正在通知服务人员接单!");
    }
}
// 进行中
public class OnGoingState implements OrderState {
    private ServiceOrder serviceOrder;

    public OnGoingState(ServiceOrder serviceOrder) {
        this.serviceOrder = serviceOrder;
    }

    @Override
    public void serviceReceiving(String order) {
        System.out.println("该状态不支持当前操作!");
    }

    @Override
    public void completedOrder(String order) {
        // 扭转状态
        serviceOrder.setState(serviceOrder.getCompletedState());
    }

    @Override
    public void print() {
        System.out.println("订单正在进行中!");
    }
}
// 已完成
public class CompletedState implements OrderState {
    private final ServiceOrder serviceOrder;

    public CompletedState(ServiceOrder serviceOrder) {
        this.serviceOrder = serviceOrder;
    }

    @Override
    public void serviceReceiving(String order) {
        System.out.println("该状态不支持当前操作!");
    }

    @Override
    public void completedOrder(String order) {
        // 已完成
    }

    @Override
    public void print() {
        System.out.println("该订单已完成!");
    }
}
// 服务订单类
public class ServiceOrder {

    private final OrderState waitingState;
    private final OrderState ongoingState;
    private final OrderState completedState;
    private final String order;
    private OrderState state;

    public ServiceOrder(String order) {
        this.waitingState = new WaitingState(this);
        this.ongoingState = new OnGoingState(this);
        this.completedState = new CompletedState(this);
        this.order = order;
        this.state = this.getWaitingState();
        this.print();
    }

    public OrderState getWaitingState() {
        return waitingState;
    }

    public OrderState getOngoingState() {
        return ongoingState;
    }

    public OrderState getCompletedState() {
        return completedState;
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    public void serviceReceiving() {
        state.serviceReceiving(order);
        print();
    }

    public void completedOrder() {
        state.completedOrder(order);
        print();
    }

    public void print() {
        state.print();
    }
}

// 测试
public static void main(String[] args) throws InterruptedException {
    String order = "\n====\n服务:远程修BUG\n价格:500¥\n====\n";
    ServiceOrder serviceOrder = new ServiceOrder(order);
    // 订单进行中...
    serviceOrder.serviceReceiving();
    // 服务人员已完成订单
    serviceOrder.completedOrder();
}

这样,我们就使用状态模式将它更改完了。

比起IF ELSE来说更加灵活,之后再新增状态也方便,而不是通过IF ELSE来判断。

不过一值得一提的是,状态模式可能跟策略模式很类似,但它们的"意图"却是不相同的。