這次寫State Pattern,題目是寫一個飲水機,不過因為State Pattern要寫的函式和類別會隨著State數目增加而指數上升,所以一切從簡。按扭只有「倒熱水、倒冷水、加熱、持續出水」4個,State只有「閒置、倒熱水、倒冷水、加熱、持續出水」5個。
以前java就沒有搞很懂,這次光是一開始要寫一個abstract state class就搞老半天,一下忘記加public,一下不知道要加abstract,最後改成這樣還是一直說錯…
public abstract class State{
public abstract void pressHold(void);
public abstract void pressPouringCold(void);
public abstract void pressPouringHot(void);
public abstract void pressHeating(void);
}
最後回去看投影片才知道參數例不能加void…但是不能加void的原因就不知道了…
public abstract class State{
public abstract void pressHold();
public abstract void pressPouringCold();
public abstract void pressPouringHot();
public abstract void pressHeating();
}
原本想說比較有意義的寫法,應該是按一下加熱,會切換到加熱狀態,這時候按其他鍵會沒有反應,要等到加熱完才會有反應。但是不知道怎麼寫一個函式正在跑,又可以接收別的輸入。所以最後就切到某個State就等那個State的事情做完才可以下一個input。
寫的時候發現,如果是先把介面定好,各種SubState去繼承State class,然後WaterMachine class裡面存一個State state變數,很自然的,要改變存state變數值的函式setState(State NewState)就會放在WaterMachine裡面。而為了保持WaterMachine裡面呼叫state.pressXXXX()的一致性,所以實際執行pressXXX()後要改變state的動作就會放在各SubState class裡面。為了要可以call WaterMachine裡面的setState(State NewState),在WaterMachine裡面就要改成call state.pressXXXX(this),把自己也傳進那些SubState class裡面,這樣才可以讓那些SubState class呼叫setState(State NewState)。沒想到一開始那樣定介面的話,接下來的寫法就很自然的會變成這樣寫,真是神奇!
程式碼大概長這樣
public abstract class State {
public void pressPouringCold(WaterMachine waterMachine)
{
System.out.println("Pouring Cold Water...");
waterMachine.setState(new PouringColdState());
}
public void pressPouringHot (WaterMachine waterMachine){
System.out.println("Pouring Hot Water...");
waterMachine.setState(new PouringHotState());
}
public void pressHeating(WaterMachine waterMachine){
System.out.print("Heating...");
try{
Thread.sleep(5000);
}
catch(Exception e)
{
;
}
System.out.println("Done!");
waterMachine.setState(new HeatingState());
}
public void pressHold (WaterMachine waterMachine){
System.out.println("Change to Hold State...");
waterMachine.setState(new HoldState());
}
}
public class IdleState extends State{
;
}
public class PouringHotState extends State {
@Override
public void pressPouringHot(WaterMachine waterMachine){
System.out.println("Constantly Pouring Hot Water...");
}
}
public class PouringColdState extends State{
@Override
public void pressPouringCold(WaterMachine waterMachine){
System.out.println("Constantly Pouring Cold Water...");
}
}
public class HeatingState extends State{
@Override
public void pressHeating(WaterMachine waterMachine){
System.out.println("Already Heated...");
}
}
public class HoldState extends State{
@Override
public void pressPouringHot(WaterMachine waterMachine){
System.out.print("Pouring Hot Water for a while...");
try{
Thread.sleep(5000);
}
catch(InterruptedException ie)
{
;
}
System.out.println("Done!");
waterMachine.setState(new IdleState());
}
@Override
public void pressPouringCold(WaterMachine waterMachine){
System.out.print("Pouring Cold Water for a while...");
try{
Thread.sleep(5000);
}
catch(InterruptedException ie)
{
;
}
System.out.println("Done!");
waterMachine.setState(new IdleState());
}
@Override
public void pressHold(WaterMachine waterMachine){
System.out.println("Change to Idle State...");
waterMachine.setState(new IdleState());
}
}
public class WaterMachine {
State state = new IdleState();
void setState(State NewState)
{
this.state = NewState;
}
/**
* deligate to state class
*/
public void pressPouringHot()
{
state.pressPouringHot(this);
}
public void pressPouringCold()
{
state.pressPouringCold(this);
}
public void pressHold()
{
state.pressHold(this);
}
public void pressHeating()
{
state.pressHeating(this);
}
}
最後JUnit看一看網路上的教學還是不太會,之後再說好了。
沒有留言:
張貼留言