1. 程式人生 > >走進設計模式的世界10:蹭一波雙11熱度-狀態模式

走進設計模式的世界10:蹭一波雙11熱度-狀態模式

狀態模式 :

允許物件在內部狀態改變時,改變他的行為,物件看起來好像是修改了他的類。

解釋:狀態模式允許一個物件基於內部狀態而擁有不同的行為。和程式狀態機不同,狀態模式用類代表狀態。Context會將內容委託給當前狀態物件。通過將每個狀態封裝進一個類,我們把以後需要做的任何改變區域性化了。狀態模式和策略模式有相同的類圖,但是他們的意圖不同。策略模式通常會用行為或演算法配置context類,狀態轉換state是由context控制的。使用狀態模式通常會導致設計類中的類數目增加。狀態類可以被多個context例項共享。

狀態模式樣例演示:蹭一波雙11熱度,來說訂單。

/**
    拋開電商不說,但從一個寒酸的小商城的訂單系統來說,
    他們的設計特別的繁瑣,通過一系列複雜的狀態來控制訂單的行為
    以及客戶的行為。
**/

public class Loan{
    
    // 待付款
    final static int DaiFuKuan = 0;
    // 待發貨
    final static int DaiFaHuo = 2;
    // 已發貨
    final static int YiFaHuo = 3;
    // 已收貨
    final static int YiShouHuo = 4;
    // 交易完成
    final static int JiaoYiWanCheng = 5;
    // 訂單狀態
    private int loanState;
   
    public Loan(){
        // 預設訂單建立了狀態為待付款
        loanState = DaiFuKuan;
    }
    
    // 付款
    public void fuKuan(){
        if(DaiFuKuan==state){
           System.out.println("付款成功!"); 
        }else if(DaiFaHuo==state){
           System.out.println("已經付款過,無需再次付款!");
        }else if(YiFaHuo ==state){
           System.out.println("已經發貨,無需再次付款!");
        }else if(YiShouHuo==state){
           System.out.println("已經收貨,無需再次付款!");
        }else{
           System.out.println("交易完成,無需再次付款!");
        }            
    }

    // 催促賣家發貨
    public void faHuo(){
        if(DaiFuKuan==state){
           System.out.println("您現在還未付款,無法督促賣家發貨!"); 
        }else if(DaiFaHuo==state){
           System.out.println("催促發貨成功!");
        }else if(YiFaHuo ==state){
           System.out.println("已經發貨,無需催促!");
        }else if(YiShouHuo==state){
           System.out.println("已經收貨,無需催促!");
        }else{
           System.out.println("交易完成,無需催促!");
        }     
    }
    
    // 收貨
    public void shouHuo(){
        if(DaiFuKuan==state){
           System.out.println("您現在還未付款,無法收貨!"); 
        }else if(DaiFaHuo==state){
           System.out.println("貨物未到達無法收貨!");
        }else if(YiFaHuo ==state){
           System.out.println("貨物未到達無法收貨!");
        }else if(YiShouHuo==state){
           System.out.println("收貨成功!");
        }else{
           System.out.println("交易完成,無法再次收貨!");
        }   
    }

    
}

就這樣看似完美嚴謹的一個訂單就被設計好了,但是,如果現在需要增加退款的請求呢???當然我們依然可以嚴謹的把退款的邏輯寫的很好,但是呢?為什麼我們不選擇一個捷徑呢,那麼我們就來看下面的設計。

public class LoanContext{
    // 待付款狀態
    private LoanState daiFuKuanState;
    // 待發貨狀態
    private LoanState daiFaHuoState;
    // 已發貨狀態
    private LoanState yiFaHuoState;
    // 已收貨狀態
    private LoanState yiShouHuoState;
    // 交易完成狀態
    private LoanState jiaoYiWanChengState;
    // 已退款狀態
    private LoanState yiTuiKuanState;
    
    // 當前訂單狀態
    private LoanState state;
    
    public LoanContext(){
        // 把本物件的引用交給狀態
        daiFuKuanState = new DaiFuKuanState(this);
        daiFaHuoState = new DaiFaHuoState(this);
        yiFaHuoState = new YiFaHuoState(this);
        yiShouHuoState = new YiShouHuoState(this);
        jiaoYiWanChengState = new JiaoYiWanChengState(this);
        yiTuiKuanState = new YiTuiKuanState(this);
        // 預設狀態為 待付款
        state = daiFuKuanState;
    }

    // 收貨
    public void shouHuo(){
        state.shouHuo();
    }
    // 發貨
    public void faHuo(){
        state.fahuo();
    }
    // 付款
    public void fuKuan(){
        state.fuKuan();
    }
    // 退貨
    public void tuiHuo(){
        state.tuiHuo();
    }
    
}

這樣訂單的處理類就完成了,然後整理下各個訂單的資訊

// 訂單狀態抽象類
public Abstract class LoanState{
    private LoanContext context;

    public LoanState (LoanContext context){
        this.context = context;
    }
    
    public void shouHuo();
    
    public void faHuo();
    
    public void fuKuan();
    
    public void tuiHuo();
}

/**
    待付款狀態
**/
public class DaiFuKuanState extends LoanState{
    // 收貨
    public void shouHuo(){
        System.out.println("您未付款,無法收貨");
    }

    // 付款
    public void fuKuan(){
        System.out.println("付款成功!");
        // 設定狀態為待發貨。
        context.setState(context.getDaiFaHuo());
    }

    // 發貨
    public void faHuo(){
        System.out.println("您未付款,無法發貨!");
    }
    
    // 收貨
    public void shouHuo(){
        System.out.println("您未付款,無法收貨!");
    }

    // 退款
    public void tuiKuan(){
        System.out.println("您未付款,無法退款!");
    }
}

/**
    待發貨狀態
**/
public class DaiFaHuoState extends LoanState{
     // 收貨
    public void shouHuo(){
        System.out.println("貨未發出無法收貨,無法收貨");
    }

    // 付款
    public void fuKuan(){
        System.out.println("已經付款,無法二次付款!");
    }

    // 發貨
    public void faHuo(){
        System.out.println("催促發貨成功!賣家已發貨!");
        context.setState(context.yiFaHuo());
    }
    
    // 收貨
    public void shouHuo(){
        System.out.println("貨物未到!");
    }

    // 退款
    public void tuiKuan(){
        System.out.println("貨物已發無法退款!");
    }
}

按照這種方式繼續對其他類進行修改之後,一個完整的訂單系統就完成了。通過context控制了訂單的狀態直接進行了下一步。而且增加了拓展性和可維護性!