一、是什麼
1. 定義: 封裝了基於狀態的行為,並使用委託在行為之間切換
2. 好處: 通過將每個狀態封裝到類中,將以後需要做的任何改變區域性化
3. 缺點: 使用狀態類通常會導致設計類的數量大量增加
4. 類圖如上,和策略模式的類圖相同,目的不同,策略是為了封裝互換的行為,用委託來解耦,狀態模式的目的是將狀態封裝成類,用委託來切換狀態
二、示例
場景:假設衝一杯咖啡的步驟是,1. 拿一個空杯子 2. 往杯子中新增速溶咖啡 3. 往杯子中加水
該場景中有三個狀態: 1. 空杯子 2. 裝有速溶咖啡的杯子 2. 裝水的杯子
原來的實現:
寫了個大概的假程式碼, 這裡只有拿杯子的方法,裡面就有了四個if判斷, 後面的方法還是繼續if判斷,相對麻煩一點, 當然最重要的是如果以後要變化步驟的話,整個類都在影響範圍之類。而狀態模式在這裡可以幫我們將變化區域性化
final static int NO_CUP = 0 // 還沒有杯子的狀態 final static int EMPTY_CUP = 1 // 空杯 final static int INSTANT_COFFEE_CUP = 2 // 裝有速溶咖啡粉的杯子 final static int ENJOY_CUP = 3 // 衝好咖啡, 美滋滋的杯子 // 拿杯子的方法 public void takeCup() { if (state == NO_CUP) { // 此時沒有杯子, 所以我就拿了一個空杯子 state = EMPTY_CUP; } else if (state == EMPTY_CUP) { // 已經有一個空杯子了, 不需要再拿了 } else if (state == INSTANT_COFFEE_CUP) { // 已經有一個裝有速溶咖啡粉的杯子, 不需要再拿了 } else if (state == ENJOY_CUP) { // 已經衝好咖啡了, 不需要再拿了 } }
現有的實現:
1. 狀態類
1. 1 狀態類的介面
/** * 狀態介面 */ public interface State { /** * 1. 拿杯子 */ void takeCup(); /** * 2. 往杯子中新增速溶咖啡 */ void addInstantCoffe(); /** * 3. 往杯子中加水 */ void addWater(); /** * 4. 盡情的享受咖啡 */ void enjoyCoffe(); }
1.2 沒有杯子的狀態類
/** * 0. 沒有杯子的狀態 */ public class NoCupState implements State { private MakeCoffe makeCoffe; public NoCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { makeCoffe.state = makeCoffe.emptyCupState; System.out.println("拿了一個杯子"); } @Override public void addInstantCoffe() { System.out.println("還沒有一個杯子, 需要拿個杯子"); } @Override public void addWater() { System.out.println("還沒有一個杯子, 需要拿個杯子"); } @Override public void enjoyCoffe() { System.out.println("現在還沒有杯子, 享受不了啊"); } }
1.3 空杯子的狀態
/** * 1. 有個空杯子的狀態 */ public class EmptyCupState implements State { private MakeCoffe makeCoffe; public EmptyCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { System.out.println("已經有個空杯子了, 不需要再"); } @Override public void addInstantCoffe() { this.makeCoffe.state = makeCoffe.instantCoffeCupState; System.out.println("往杯子加了速溶咖啡"); } @Override public void addWater() { System.out.println("杯子中還需要先加速溶咖啡粉, 再加水"); } @Override public void enjoyCoffe() { System.out.println("現在還是空杯子, 享受不了啊"); } }
1.4 加了速溶咖啡的狀態
/** * 2. 加了速溶咖啡的狀態 */ public class InstantCoffeCupState implements State { private MakeCoffe makeCoffe; public InstantCoffeCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { System.out.println("杯子中已經加了速溶咖啡了, 不需要在拿一個了"); } @Override public void addInstantCoffe() { System.out.println("杯子中已經加了速溶咖啡了, 不需要再放速溶咖啡了"); } @Override public void addWater() { makeCoffe.state = makeCoffe.coffeOkState; System.out.println("往有速溶咖啡的杯子裡, 加水"); } @Override public void enjoyCoffe() { System.out.println("現在杯子中還沒加水, 享受不了啊"); } }
1.5 加完水,咖啡衝好的狀態,享受咖啡
/** * 4. 咖啡衝好, 享受咖啡 */ public class CoffeOkState implements State { @Override public void takeCup() { System.out.println("咖啡已經衝好了, 不需要再拿一個杯子了"); } @Override public void addInstantCoffe() { System.out.println("咖啡已經衝好了, 不需要再加速溶咖啡了"); } @Override public void addWater() { System.out.println("咖啡已經衝好了, 不需要再加水了"); } @Override public void enjoyCoffe() { System.out.println("享受咖啡咯"); } }
2. 製作咖啡的類
/** * 製作咖啡的類 */ public class MakeCoffe { /** * 這杯咖啡的狀態 */ public State state; /** * 沒有杯子狀態 */ public NoCupState noCupState; /** * 有一個空杯子狀態 */ public EmptyCupState emptyCupState; /** * 杯子裡有速溶咖啡粉狀態 */ public InstantCoffeCupState instantCoffeCupState; /** * 衝好咖啡狀態 */ public CoffeOkState coffeOkState; public MakeCoffe() { this.noCupState = new NoCupState(this); this.emptyCupState = new EmptyCupState(this); this.instantCoffeCupState = new InstantCoffeCupState(this); this.coffeOkState = new CoffeOkState(); // 設定預設狀態 this.state = this.noCupState; } // 拿杯子 public void takeCup() { state.takeCup(); } // 加入速溶咖啡 public void addInstantCoffe() { state.addInstantCoffe(); } // 加水 public void addWater() { state.addWater(); } public void enjoyCoffe() { state.enjoyCoffe(); } }
3. 測試
/** * 享受咖啡測試類 */ public class EnjoyCoffeMain { public static void main(String[] args) { MakeCoffe makeCoffe = new MakeCoffe(); makeCoffe.takeCup(); makeCoffe.addInstantCoffe(); makeCoffe.addWater(); makeCoffe.enjoyCoffe(); } } // 控制檯顯示 拿了一個杯子 往杯子加了速溶咖啡 往有速溶咖啡的杯子裡, 加水 享受咖啡咯
1. 恭喜這個程式猿在沒有寫很多IF判斷的情況下,成功享受到咖啡, 狀態模式這裡我覺得好處就是可以將變化分開封裝,以後 要是某個狀態中的操作改了,不需要查詢整個IF了,找到對應類修改。
2. 或者以後新增某個狀態的話,如卡布奇諾需要加奶加糖等,就不需要修改IF, 而是新增狀態,修改部分狀態中的程式碼
3. 帶來的缺點就是,增加了很多的類
三、總結
想想自己兩年前理解的狀態的模式,現在比以前更理解一點了