一、定義
狀態模式:允許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。
二、分析
狀態模式把不同的狀態封裝成類,並將對應的動作委託到對應的類中,只要狀態一改變,對應的動作與會隨之改變。
狀態模式主要應用於業務邏輯中包含大量的狀態判斷的條件語句。我們可以把各個狀態抽象出來,然後實現和各個狀態相關的業務操作。
狀態模式的優點在於:
- 封裝了轉換的規則:改變狀態的方法放在具體狀態類中切換;
- 把狀態和狀態有關的行爲放在一個類中,便於添加新的狀態;只需要編寫新的狀態,然後切換到這個狀態即可。
三、類圖
下面是狀態模式的類圖:
四、代碼實現
我們使用代碼來實現狀態模式:
源碼:gitee
項目結構如下:
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}
*/