設計模式之 狀態模式

一、定義

狀態模式:允許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。

二、分析

狀態模式把不同的狀態封裝成類,並將對應的動作委託到對應的類中,只要狀態一改變,對應的動作與會隨之改變。

狀態模式主要應用於業務邏輯中包含大量的狀態判斷的條件語句。我們可以把各個狀態抽象出來,然後實現和各個狀態相關的業務操作。

狀態模式的優點在於:

  1. 封裝了轉換的規則:改變狀態的方法放在具體狀態類中切換;
  2. 把狀態和狀態有關的行爲放在一個類中,便於添加新的狀態;只需要編寫新的狀態,然後切換到這個狀態即可。

三、類圖

下面是狀態模式的類圖:

状态模式

四、代碼實現

我們使用代碼來實現狀態模式:

源碼:gitee

項目結構如下:

image-20210201173012235

1.抽象狀態類 OrderState.java

package state;

/**
 * 訂單狀態抽象
 *
 * @author lixin
 */
public interface OrderState {

    /**
     * 查詢訂單的詳細信息
     *
     * @param context 訂單查詢類
     * @param orderId 訂單ID
     * @return 訂單詳情實體
     */
    OrderDetail findOrderDetail(OrderDetailContext context, Long orderId);

}

2.創建數據實體 OrderDetail.java

package state;

/**
 * 訂單詳情實體
 *
 * @author lixin
 */
public class OrderDetail {
    private Long id;
    private String name;
    private String orderNo;
    private Integer status;

    public OrderDetail(Long id, String name, String orderNo, Integer status) {
        this.id = id;
        this.name = name;
        this.orderNo = orderNo;
        this.status = status;
    }

    @Override
    public String toString() {
        return "OrderDetail{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", orderNo='" + orderNo + '\'' +
                ", status=" + status +
                '}';
    }

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

}

3.實現具體狀態的操作邏輯 PayIngState.java PayCompleteState.java OrderExpireState.java

// PayIngState.java
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 訂單支付中
 *
 * @author lixin
 */
public class PayIngState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("訂單支付中...");
        OrderDetail orderDetail = findBiId(orderId);
        updateOrderState(orderDetail.getOrderNo());
        return findBiId(orderId);
    }

    /**
     * 到微信上查詢訂單是否交易完成
     * 如果完成就更新一下訂單得到的狀態
     *
     * @param orderNo 訂單號
     */
    private void updateOrderState(String orderNo) {
        System.out.println("根據訂單號到微信支付同步訂單狀態...");
    }

    /**
     * 根據訂單ID查詢訂單信息
     *
     * @param orderId 訂單ID
     * @return 訂單信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根據orderId=%d查詢到訂單信息...", orderId));
        return new OrderDetail(1L, "手續費", "ZM2021021016560458", 0);
    }

}

// PayCompleteState.java 
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 訂單支付完成
 *
 * @author lixin
 */
public class PayCompleteState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("訂單支付完成...");
        return findBiId(orderId);
    }

    /**
     * 根據訂單ID查詢訂單信息
     *
     * @param orderId 訂單ID
     * @return 訂單信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根據orderId=%d到完成的訂單表中查詢記錄的信息...", orderId));
        return new OrderDetail(2L, "套餐3費用", "ZM2021021016562514", 1);
    }
}


// OrderExpireState.java
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 訂單過期
 *
 * @author lixin
 */
public class OrderExpireState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("訂單過期...");
        return findBiId(orderId);
    }

    /**
     * 根據訂單ID查詢訂單信息
     *
     * @param orderId 訂單ID
     * @return 訂單信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根據orderId=%d到過期訂單表中查詢信息...", orderId));
        return new OrderDetail(3L, "套餐99費用", "ZM2021021016560345", -1);
    }
}

4.創建使用狀態的類 OrderDetailContext.java

package state;

/**
 * 訂單操作類
 *
 * @author lixin
 */
public class OrderDetailContext {
    private OrderState orderState;

    public OrderDetailContext() {
    }

    public OrderState getOrderState() {
        return orderState;
    }

    public void setOrderState(OrderState orderState) {
        this.orderState = orderState;
    }

    /**
     * 查詢訂單詳情
     *
     * @param orderId 訂單ID
     * @return 訂單詳情
     */
    public OrderDetail findOrderDetail(Long orderId) {
        return orderState.findOrderDetail(this, orderId);
    }
}

5.創建測試類

package state;

import state.impl.OrderExpireState;
import state.impl.PayCompleteState;
import state.impl.PayIngState;

/**
 * 狀態模式測試類
 *
 * @author lixin
 */
public class StateDemoMain {

    public static void main(String[] args) {
        // 創建Context使用狀態
        OrderDetailContext context = new OrderDetailContext();

        // 改變狀態
        context.setOrderState(new PayIngState());
        // 執行對應狀態的處理方法
        OrderDetail detail1 = context.findOrderDetail(1L);
        System.out.println(detail1);

        System.out.println("==================");
        // 切換到另外一個狀態
        context.setOrderState(new PayCompleteState());
        // 執行對應狀態的處理方法
        OrderDetail detail2 = context.findOrderDetail(2L);
        System.out.println(detail2);

        System.out.println("==================");
        // 切換到另外一個狀態
        context.setOrderState(new OrderExpireState());
        // 執行對應狀態的處理方法
        OrderDetail detail3 = context.findOrderDetail(3L);
        System.out.println(detail3);
    }

}

/* 輸出結果:

訂單支付中...
根據orderId=1查詢到訂單信息...
根據訂單號到微信支付同步訂單狀態...
根據orderId=1查詢到訂單信息...
OrderDetail{id=1, name='手續費', orderNo='ZM2021021016560458', status=0}
==================
訂單支付完成...
根據orderId=2到完成的訂單表中查詢記錄的信息...
OrderDetail{id=2, name='套餐3費用', orderNo='ZM2021021016562514', status=1}
==================
訂單過期...
根據orderId=3到過期訂單表中查詢信息...
OrderDetail{id=3, name='套餐99費用', orderNo='ZM2021021016560345', status=-1}

*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章