走進設計模式的世界10:蹭一波雙11熱度-狀態模式
阿新 • • 發佈:2018-11-14
狀態模式 :
允許物件在內部狀態改變時,改變他的行為,物件看起來好像是修改了他的類。
解釋:狀態模式允許一個物件基於內部狀態而擁有不同的行為。和程式狀態機不同,狀態模式用類代表狀態。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控制了訂單的狀態直接進行了下一步。而且增加了拓展性和可維護性!