設計模式之狀態模式(二)

  • 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所要組合的策略對象是哪一個。

等等等等,之前不是說有十次抽中一次的遊戲嗎?怎麼還沒寫出來呢?哈哈哈哈,不急不急,以上內容你都消化了嗎?如果你消化的話,請你耐心等待,倘若沒有,那請你先好好學習這些吧。我將在下次把抽獎這個搞定。

拜拜!

「奔跑吧攻城獅」感謝大家的關注,現在後台回復「設計模式」贈你小編精心挑選設計模式書籍。小編最近開竅,組建了一個技術交流群,回復「加群」即可解鎖。