在上一次的文章里,我們看到,需求的變更,迫使我們需要重新改造現有的糖果機代碼來符合這個新提的需求。但是,也並沒有難倒我們,至少我們在文末給出了思路和類圖,不知道你想的怎麼樣了呢。 我們不來虛的,直接進入正題,開啟我們的學習之旅。 實現我們的狀態類 現在是實現一個狀態的時候了:我們知道我們要的行為是什 ...
在上一次的文章里,我們看到,需求的變更,迫使我們需要重新改造現有的糖果機代碼來符合這個新提的需求。但是,也並沒有難倒我們,至少我們在文末給出了思路和類圖,不知道你想的怎麼樣了呢。
我們不來虛的,直接進入正題,開啟我們的學習之旅。
實現我們的狀態類
現在是實現一個狀態的時候了:我們知道我們要的行為是什麼,我們只需要把它變成代碼。我們打算完全遵守所寫下的狀態機代碼,但是這一次是分散在不同的類中。比如我們以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所要組合的策略對象是哪一個。
等等等等,之前不是說有十次抽中一次的游戲嗎?怎麼還沒寫出來呢?哈哈哈哈,不急不急,以上內容你都消化了嗎?如果你消化的話,請你耐心等待,倘若沒有,那請你先好好學習這些吧。我將在下次把抽獎這個搞定。
拜拜!
「奔跑吧攻城獅」感謝大家的關註,現在後臺回覆「設計模式」贈你小編精心挑選設計模式書籍。小編最近開竅,組建了一個技術交流群,回覆「加群」即可解鎖。