設計模式-狀態模式

煮詩君發表於2021-05-01

狀態模式允許其內部狀態發生變化的時候改變其行為,貌似是物件改變了類。

一個物件的行為取決於一個或者多個動態變化的屬性,這些屬性叫做狀態,比如訂單的支付狀態;而這些訂單狀態的值是預先知道的,已支付、未支付;當訂單在客戶操作過程中可能會改變支付狀態,訂單從未支付到已支付,就形成訂單真正成功下單。

適用場景:

  • 一個物件的行為取決於他的狀態,並且它必須在執行時根據狀態改變它的行為;
  • 一個操作中含有龐大的多分支結構,並且這些分支決定於物件的狀態。

先看下 UML 類圖


1089494-33f04da8eee73267.jpg

上下文類Context: 維護一個ConcreteState子類的例項,這個例項定義當前狀態;
抽象狀態類State: 定義一個介面以封裝與Context的一個特定狀態相關的行為;
具體狀態類ConcreteState: 每一子類實現一個與Context的一個狀態相關的行為;

模擬下訂單的狀態改變:
總共有未支付、已支付、申請退款,退款中,退款完成訂單結束幾個過程,過程中每個狀態需要依賴上個狀態,這個在本例中沒有做判斷,僅僅展示狀態變化的魔力。
首先把訂單狀態這個抽象類給寫出來

public abstract class OrderStatus {

    protected Order order;
    protected String name;
    
    public OrderStatus(Order order,String name) {
        this.order=order;
        this.name=name;
    }
    
    public abstract OrderStatus next(Order order);
    
    public void print(){
        System.out.println("當前狀態"+this.name);
    }
}

然後把訂單類寫出

public class Order {

    private OrderStatus status;
    
    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }
//other properties
    
}

他們之間是秤不離砣,你中有我,我中有你;
接下來看下具體的狀態:
第一個是沒有支付的狀態,也就是訂單預設狀態,甚至可以初始化到訂單內部,這裡也單獨拿出來

public class NoPayStatus extends OrderStatus{

    public NoPayStatus(Order order,String name) {
        super(order,name);
    }

    @Override
    public OrderStatus next(Order order) {
        print();
        OrderStatus s=new PayStatus(order,"已支付");
        order.setStatus(s);
        return s;
    }

}

第二,已支付狀態

public class PayStatus extends OrderStatus {

    public PayStatus(Order order, String name) {
        super(order, name);
    }

    @Override
    public OrderStatus next(Order order) {
        print();
        return new ApplyDrawbackStatus(order, "申請退款");

    }

}

第三是申請退款,第三部可以根據實際業務情況直接到第五狀態

public class ApplyDrawbackStatus extends OrderStatus {

    public ApplyDrawbackStatus(Order order, String name) {
        super(order, name);
    }

    @Override
    public OrderStatus next(Order order) {
        print();
        return new DrawbackStatus(order, "訂單回款中");

    }

}

第四是退款中

public class DrawbackStatus extends OrderStatus {

    public DrawbackStatus(Order order, String name) {
        super(order, name);
    }

    @Override
    public OrderStatus next(Order order) {
        print();
        return new CompleteStatus(order, "訂單回款完成,徹底結束");

    }

}

第五是訂單徹底完成

public class CompleteStatus extends OrderStatus {

    public CompleteStatus(Order order, String name) {
        super(order, name);
    }

    @Override
    public OrderStatus next(Order order) {
        print();
        return null;

    }

}

最後看下客戶端

public class Client {

    public static void main(String[] args) {
        Order order=new Order();
        order.setStatus(new NoPayStatus(order, "未支付"));
        OrderStatus status=order.getStatus();
        status=status.next(order);
        System.out.println("---------------");
        status=status.next(order);
        System.out.println("---------------");
        status=status.next(order);
        System.out.println("---------------");
        status=status.next(order);
        System.out.println("---------------");
        status=status.next(order);
    }

}
/**  ----Result----
當前狀態未支付
---------------
當前狀態已支付
---------------
當前狀態申請退款
---------------
當前狀態訂單回款中
---------------
當前狀態訂單回款完成,徹底結束
*/

客戶端需要校驗空指標,這裡不再贅述.

訂單狀態改變,也就是在 next 方法中需要做一些持久化操作和業務校驗,也許更加符合業務需要。

相關文章