設計模式之狀態模式(二)
- 2019 年 10 月 3 日
- 筆記
在上一次的文章里,我們看到,需求的變更,迫使我們需要重新改造現有的糖果機代碼來符合這個新提的需求。但是,也並沒有難倒我們,至少我們在文末給出了思路和類圖,不知道你想的怎麼樣了呢。
我們不來虛的,直接進入正題,開啟我們的學習之旅。
實現我們的狀態類
現在是實現一個狀態的時候了:我們知道我們要的行為是什麼,我們只需要把它變成代碼。我們打算完全遵守所寫下的狀態機代碼,但是這一次是分散在不同的類中。比如我們以NoQuarterState類為例。
public class NoQuarterState implements State { GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { System.out.println("You inserted a quarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); } public void ejectQuarter() { System.out.println("You haven't inserted a quarter"); } public void turnCrank() { System.out.println("You turned, but there's no quarter"); } public void dispense() { System.out.println("You need to pay first"); } }
在完成這些狀態類之前,我們需要重新改造糖果機,好讓你了解這一切的原理。我們把原來使用整數代表的狀態改為狀態對象:
State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State state; int count = 0;
這樣,我們就有了一個完整的糖果機類
public class GumballMachine { State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State state; int count = 0; public GumballMachine(int numberGumballs) { soldOutState = new SoldOutState(this); noQuarterState = new NoQuarterState(this); hasQuarterState = new HasQuarterState(this); soldState = new SoldState(this); this.count = numberGumballs; if (numberGumballs > 0) { state = noQuarterState; } else { state = soldOutState; } } public void insertQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } void releaseBall() { System.out.println("A gumball comes rolling out the slot..."); if (count != 0) { count = count - 1; } } // 後面部分省略 }
好了,這樣子,我們就能繼續實現更多的狀態類了。比如我們能實現HasQuarterState和SoldState類
public class HasQuarterState implements State { GumballMachine gumballMachine; public HasQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { System.out.println("You can't insert another quarter"); } public void ejectQuarter() { System.out.println("Quarter returned"); gumballMachine.setState(gumballMachine.getNoQuarterState()); } public void turnCrank() { System.out.println("You turned..."); gumballMachine.setState(gumballMachine.getSoldState()); } public void dispense() { System.out.println("No gumball dispensed"); } }
public class SoldState implements State { GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } public void insertQuarter() { System.out.println("Please wait, we're already giving you a gumball"); } public void ejectQuarter() { System.out.println("Sorry, you already turned the crank"); } public void turnCrank() { System.out.println("Turning twice doesn't get you another gumball!"); } public void dispense() { gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0) { gumballMachine.setState(gumballMachine.getNoQuarterState()); } else { System.out.println("Oops, out of gumballs!"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } }
檢查一下,到目前為止我們做了啥
你現在有了一個糖果機的實現,他在結構上和前一個版本差異很大,但是功能上卻是一樣的。我們發現,你已經實現了以下幾點:
-
將每個狀態的行為局部化到它自己的類中
-
將容易產生問題的if語句刪除,以方便日後的維護
-
讓每個狀態「對修改關閉」,讓糖果機「對擴展開放」,因為可以加入新的狀態類
-
創建一個新的代碼基和類結構,這更能映射萬能糖果公司的圖,而且更容易閱讀和理解
定義狀態模式
是的,就在剛才,我們已經實現了狀態模式。現在讓我們來看看什麼是狀態模式。
狀態模式允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它的類。
讓我們好好看下狀態模式的類圖:
這個類圖和策略模式的類圖是一樣的。但是雖然類圖是一樣的,但是兩個模式的差別在於它們的「意圖」不同。狀態模式將一群行為封裝在狀態對象中,context行為隨時可委託到那些狀態對象中的一個。對於策略模式而言,客戶通常主動指定context所要組合的策略對象是哪一個。
等等等等,之前不是說有十次抽中一次的遊戲嗎?怎麼還沒寫出來呢?哈哈哈哈,不急不急,以上內容你都消化了嗎?如果你消化的話,請你耐心等待,倘若沒有,那請你先好好學習這些吧。我將在下次把抽獎這個搞定。
拜拜!
「奔跑吧攻城獅」感謝大家的關注,現在後台回復「設計模式」贈你小編精心挑選設計模式書籍。小編最近開竅,組建了一個技術交流群,回復「加群」即可解鎖。