Head Frist 設計模式11-狀態模式模式
如果餓了就喫,困了就睡,渴了就喝,人生就太無趣了
代碼地址:https://github.com/keer123456789/MY_STUDY_LIFE/tree/master/src/main/java/study/Module/Module_State
1.定義
1.1概念
狀態模式允許對象在內部狀態改變時改變它的行爲,對象看起來好像修改了它的類。
1.2類圖
- 將所有的狀態抽象出一個共同接口
state
,讓不同的狀態都實現這個接口,這樣就可以實現不同狀態的轉換 Context
類擁有一些狀態,一旦有人調用request()
方法,就委託到狀態state
來實現。ConcreteState
類處理來自Context
的請求。
2.例子(糖果機)
給一個投幣糖果機進行程序設計。每次投25美分,就可以獲得一個口香糖。
2.1 狀態圖
現在需要給一個糖果機的程序進行設計,如圖2:狀態圖
一共是4個狀態:
- 沒有25分錢
- 有25分錢
- 糖果售罄
- 售出糖果
有5個動作:每一個動作都是糖果機的接口,調用每一個動作,都會造成狀態的轉換
- 投入25美分
- 轉動曲柄
- 退回25美分
- 發放糖果
- 填入糖果
2.2 類圖
如圖3:
- 根據剛纔得分析,將能改變狀態的5個動作進行抽象,形成
State
接口,接口方法分別是:insertQuarter()
投幣,ejectQuart()
退幣,turnCrank()
轉動曲柄,dispense()
分配糖果,refill()
添加糖果 - 一共有四個狀態,都實現
State
接口,每個狀態對不同的動作接口做出不同的反應。
2.3 分析流程
如圖4
- 糖果機的狀態爲
沒有25美分NoQuarter
,此時有投幣動作insertQuarter()
時,將動作委託到NoQuarter
狀態,進行狀態轉換,切換到HasQuarter
有25美分狀態 - 糖果機接收到轉動曲柄動作
turnCrank()
,將動作委託到當前狀態,狀態進行轉換,切換到Sold
售出糖果狀態 - 糖果機接收到出售糖果動作
dispense()
,將動作委託到當前狀態,狀態進行轉換,切換到NoQuarter
無25美分狀態
3.代碼
3.1 狀態接口和實現類
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:29
* @Description: 狀態接口
*/
public interface State {
/**
* 投入25美分
*/
void insertQuarter();
/**
* 退回25美分
*/
void ejectQuarter();
/**
* 轉動曲柄
*/
void turnCrank();
/**
* 分配糖果
*/
void dispense();
/**
* 重新添加糖果
*/
void refill();
}
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:43
* @Description: 沒有25美分狀態
*/
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You inserted a quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("You haven't inserted a quarter");
}
@Override
public void turnCrank() {
System.out.println("You turned, but there's no quarter");
}
@Override
public void dispense() {
System.out.println("You need to pay first");
}
@Override
public void refill() {
}
@Override
public String toString() {
return "waiting for quarter";
}
}
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:45
* @Description: 有25美分狀態
*/
public class HasQuarterState implements State{
GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You can't insert another quarter");
}
@Override
public void ejectQuarter() {
System.out.println("Quarter returned");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("You turned...");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("No gumball dispensed");
}
@Override
public void refill() {
}
@Override
public String toString() {
return "waiting for turn of crank";
}
}
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:33
* @Description: 售出糖果狀態
*/
public class SoldState implements State{
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("Please wait, we're already giving you a gumball");
}
@Override
public void ejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
@Override
public void turnCrank() {
System.out.println("Turning twice doesn't get you another gumball!");
}
@Override
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());
}
}
@Override
public void refill() {
}
@Override
public String toString() {
return "dispensing a gumball";
}
}
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:40
* @Description: 售罄狀態
*/
public class SoldOutState implements State {
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You can't insert a quarter, the machine is sold out");
}
@Override
public void ejectQuarter() {
System.out.println("You can't eject, you haven't inserted a quarter yet");
}
@Override
public void turnCrank() {
System.out.println("You turned, but there are no gumballs");
}
@Override
public void dispense() {
System.out.println("No gumball dispensed");
}
@Override
public void refill() {
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public String toString() {
return "sold out";
}
}
3.2 糖果機代碼
**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:35
* @Description: 糖果機
*/
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;
}
}
int getCount() {
return count;
}
void refill(int count) {
this.count += count;
System.out.println("The gumball machine was just refilled; it's new count is: " + this.count);
state.refill();
}
void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public State getSoldOutState() {
return soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public State getSoldState() {
return soldState;
}
@Override
public String toString() {
StringBuffer result = new StringBuffer();
result.append("\nMighty Gumball, Inc.");
result.append("\nJava-enabled Standing Gumball Model #2020");
result.append("\nInventory: " + count + " gumball");
if (count != 1) {
result.append("s");
}
result.append("\n");
result.append("Machine is " + state + "\n");
return result.toString();
}
}
3.3 測試代碼
/**
* @BelongsProject: MY_STUDY_LIFE
* @BelongsPackage: study.Module.Module_State
* @Author: keer
* @CreateTime: 2020-03-09 14:53
* @Description: 測試類
*/
public class GumballMachineTestDrive {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(2);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.refill(5);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}