合工大很牛很牛牛

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            14 Posts :: 1 Stories :: 37 Comments :: 0 Trackbacks
           一個糖果機,有四個狀態,狀態圖如下:

          最基本的實現思路如下:用四個整型數表示四種狀態,用四個函數表達四個操作,每次進行操作的時候都要判斷一下是否處于可進行這步操作的狀態,操作完成后,需要更新狀態到下一步。

          package javaapplication41;

          public class Main {

              public static void main(String[] args) {

                  GumballMachine gm = new GumballMachine();

                  gm.addGumballsToMachine(2);

                  gm.insertQuarter();

                  gm.turnsCrank();

                  System.out.println("------------------");

                  gm.insertQuarter();

                  gm.insertQuarter();

                  gm.turnsCrank();

                  gm.ejectQuarter();

                  gm.turnsCrank();

              }

          }

          class GumballMachine {

              final int SOLD_OUT = 0;

              final int NO_QUARTER = 1;

              final int HAS_QUARTER = 2;

              final int SOLD = 3;

              int state;

              int gumballs = 0;

              public GumballMachine() {

                  state = SOLD_OUT;

              }

              public void insertQuarter() {

                  if (state == NO_QUARTER) {

                      System.out.println("inserting the quarter");

                      state = HAS_QUARTER;

                  }

                  else if (state == HAS_QUARTER) {

                      System.out.println("already has the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

              }

              public void ejectQuarter() {

                  if (state == HAS_QUARTER) {

                      System.out.println("ejecting the quarter....");

                      state = NO_QUARTER;

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

              }

              public void turnsCrank() {

                  if (state == HAS_QUARTER) {

                      System.out.println("turning on the crank");

                      state = SOLD;

                      dispense();           

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

              }

              private void dispense() {

                  if (state == SOLD) {

                      if (gumballs == 0) {

                          System.out.println("out of gumballs");

                          state = SOLD_OUT;

                      }

                      else {

                          System.out.println("dispensing the gumball");

                          gumballs--;

                          System.out.println("there are " + gumballs + " gumballs in the machine.");

                          state = NO_QUARTER;

                      }

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == HAS_QUARTER) {

                      System.out.println("you haven't turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

              }

              public void addGumballsToMachine(int num) {

                  gumballs += num;

                  System.out.println("adding " + num + " gumballs to the machine.");

                  System.out.println("there are " + gumballs + " gumballs in the machine.");

                  System.out.println("--------------------");

                  if (gumballs > 0) {

                      state = NO_QUARTER;

                  }

              }

          }

          現在添加一個新的流程:當turns crank的時候,判斷是否為1/10概率產生的幸運兒,如果是,則彈出兩個糖果,如果不是,則仍彈出一個糖果。


          實現如下:

          package javaapplication41;

          public class Main {

              public static void main(String[] args) {

                  GumballMachine gm = new GumballMachine();

                  gm.addGumballsToMachine(2);

                  gm.insertQuarter();

                  gm.turnsCrank();

                  System.out.println("------------------");

                  gm.insertQuarter();

                  gm.insertQuarter();

                  gm.turnsCrank();

                  gm.ejectQuarter();

                  gm.turnsCrank();

              }

          }

          class GumballMachine {

              final int SOLD_OUT = 0;

              final int NO_QUARTER = 1;

              final int HAS_QUARTER = 2;

              final int SOLD = 3;

              final int SOLD_TO_WINNER = 4;

              int state;

              int gumballs = 0;

              public GumballMachine() {

                  state = SOLD_OUT;

              }

              public void insertQuarter() {

                  if (state == NO_QUARTER) {

                      System.out.println("inserting the quarter");

                      state = HAS_QUARTER;

                  }

                  else if (state == HAS_QUARTER) {

                      System.out.println("already has the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

                  else if (state == SOLD_TO_WINNER) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

              }

              public void ejectQuarter() {

                  if (state == HAS_QUARTER) {

                      System.out.println("ejecting the quarter....");

                      state = NO_QUARTER;

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

                  else if (state == SOLD_TO_WINNER) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

              }

              public void turnsCrank() {

                  if (state == HAS_QUARTER) {

                      System.out.println("turning on the crank");

                      state = SOLD;

                      dispense();

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == SOLD) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

                  else if (state == SOLD_TO_WINNER) {

                      System.out.println("already has the quarter and have turn the crank");

                  }

              }

              private void dispense() {

                  if (state == SOLD) {

                      if (gumballs == 0) {

                          System.out.println("out of gumballs");

                          state = SOLD_OUT;

                      }

                      else {

                          System.out.println("dispensing the gumball");

                          gumballs--;

                          System.out.println("there are " + gumballs + " gumballs in the machine.");

                          state = NO_QUARTER;

                      }

                  }

                  else if (state == SOLD_TO_WINNER) {

                      if (gumballs == 0) {

                          System.out.println("out of gumballs");

                          state = SOLD_OUT;

                      }

                      else if (gumballs == 1) {

                          System.out.println("dispensing the gumball");

                          gumballs--;

                          System.out.println("there are " + gumballs + " gumballs in the machine.");

                          state = SOLD_OUT;

                      }

                      else if (gumballs > 1) {

                          System.out.println("dispensing the 2 gumballs");

                          gumballs -= 2;

                          System.out.println("there are " + gumballs + " gumballs in the machine.");

                          state = NO_QUARTER;

                      }

                  }

                  else if (state == NO_QUARTER) {

                      System.out.println("you haven't insert the quarter");

                  }

                  else if (state == HAS_QUARTER) {

                      System.out.println("you haven't turn the crank");

                  }

                  else if (state == SOLD_OUT) {

                      System.out.println("there is no gumballs in the machine");

                  }

              }

              public void addGumballsToMachine(int num) {

                  gumballs += num;

                  System.out.println("adding " + num + " gumballs to the machine.");

                  System.out.println("there are " + gumballs + " gumballs in the machine.");

                  System.out.println("--------------------");

                  if (gumballs > 0) {

                      state = NO_QUARTER;

                  }

              }

          }

          可見,為了添加一個流程,我們首先需要添加一個狀態SOLD_TO_WINNER = 4,然后在每個流程里面都要判斷一下是否處于這個狀態,故而每個流程都添加了一個else if….

          這樣的代碼,維護起來是可怕的,也就是說,這樣的設計思路是不易于擴展的。

          看到上面的程序,讓我想到了以前寫的“郵件收發程序”,繁復的else if…判斷語句讓我修改到最后,實在連看都不想看!不過好了,現在有了state pattern,專門處理怎樣寫業務流程。

          State Pattern 的前提條件是:經常發生改變的是狀態(也就是業務流程),而不是“操作”。在上面的例子中,我們把四個“操作”寫成了類,但發生變化的不是操作,而是if…else中的狀態。所以反其道而行之,我們把各個狀態寫成類(把易變化的隔離的單獨的類里面去)。如下:(未增加新狀態前)

          package javaapplication42;

          public class Main {

              public static void main(String[] args) {

                  GumballMachine gm = new GumballMachine();

                  gm.addGumballs(2);

                  gm.state.insertQuarter();//并沒有指明是哪種狀態,全部都用state,這就是代理

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.ejectQuarter();

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

                  gm.addGumballs(1);

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

              }

          }

          interface State { //四個狀態都繼承它,這樣我們可以“代理”,每個狀態都有如下四個操作。

              public void insertQuarter();

              public void ejectQuarter();

              public void turnCrank();

              public void dispense();

          }

          class GumballMachine {

              State state;

              State noQuarterState;

              State hasQuarterState;

              State soldState;

              State soldOutState;

              int gumballNum;//機器內糖果的數量

              public GumballMachine() {

                  noQuarterState = new NoQuarterState(this);

                  hasQuarterState = new HasQuarterState(this);

                  soldState = new SoldState(this);

                  soldOutState = new SoldOutState(this);

                  this.state = soldOutState;//initialize "state",這個state將貫穿整個執行過程

                  gumballNum = 0;

              }

              public void setState(State state) {

                  this.state = state;

              }

              public void play() {

                  state.insertQuarter();

                  state.turnCrank();

                  state.dispense();

              }

              public void addGumballs(int num) {

                  gumballNum += num;

                  if (gumballNum > 0) {

                      this.state = noQuarterState;

                  }

                  System.out.println("the machine has "+gumballNum+" gumball(s)");

              }

          }

          class NoQuarterState implements State {

              GumballMachine gm;

              public NoQuarterState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                 System.out.println("insert a quarter...");

                  gm.setState(gm.hasQuarterState);//執行完后,改變狀態

              }

              public void ejectQuarter() {

                  System.out.println("you can't eject quarter, for you haven't insert yet 1");

              }

              public void turnCrank() {

                  System.out.println("you can't turn crank, for you haven't insert yet 2");

              }

              public void dispense() {

                  System.out.println("you can't dispense, for you haven't insert yet 3");

              }

          }

          class HasQuarterState implements State {

              GumballMachine gm;

              public HasQuarterState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  System.out.println("you can't insert quarter, for you have insert one already");

              }

              public void ejectQuarter() {

                  System.out.println("eject quarter...");

                  gm.setState(gm.noQuarterState);

              }

              public void turnCrank() {

                  System.out.println("turning the crank...");

                  gm.setState(gm.soldState);

                  gm.state.dispense();

              }

              public void dispense() {

                  System.out.println("when you turn the crank, the machine will dispense the gumball");

              }

          }

          class SoldState implements State {

              GumballMachine gm;

              public SoldState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void ejectQuarter() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void turnCrank() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void dispense() {

                  gm.gumballNum--;

                  System.out.println("dispense one gumball...");

                  if (gm.gumballNum > 0) {

                      gm.setState(gm.noQuarterState);

                  }

                  else {

                      System.out.println("Machine has no gumball");

                      gm.setState(gm.soldOutState);

                  }

              }

          }

          class SoldOutState implements State {

              GumballMachine gm;

              public SoldOutState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  System.out.println("you can't insert quarter, for the machine has no gumball");

              }

              public void ejectQuarter() {

                  System.out.println("you can't eject quarter, for the machine has no gumball");

              }

              public void turnCrank() {

                  System.out.println("you can't turn crank, for the machine has no gumball");

              }

              public void dispense() {

                  System.out.println("you can't dispense, for the machine has no gumball");

              }

          }


          現在,我們新增
          SoldToWinnerState流程(1/10的概率獲得兩個gumball):

          package javaapplication42;

          import java.util.Random;

          public class Main {

              public static void main(String[] args) {

                  GumballMachine gm = new GumballMachine();

                  gm.addGumballs(2);

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.ejectQuarter();

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

                  gm.addGumballs(1);

                  gm.state.insertQuarter();

                  gm.state.turnCrank();

              }

          }

          interface State {

              public void insertQuarter();

              public void ejectQuarter();

              public void turnCrank();

              public void dispense();

          }

          class GumballMachine {

              State state;

              State noQuarterState;

              State hasQuarterState;

              State soldState;

              State soldOutState;

              State soldToWinnerState;

              int gumballNum;//機器內糖果的數量

              public GumballMachine() {

                  noQuarterState = new NoQuarterState(this);

                  hasQuarterState = new HasQuarterState(this);

                  soldState = new SoldState(this);

                  soldOutState = new SoldOutState(this);

                  soldToWinnerState = new SoldToWinnerState(this);

                  this.state = soldOutState;//initialize "state",這個state將貫穿整個執行過程

                  gumballNum = 0;

              }

              public void setState(State state) {

                  this.state = state;

              }

              public void play() {

                  state.insertQuarter();

                  state.turnCrank();

                  state.dispense();

              }

              public void addGumballs(int num) {

                  gumballNum += num;

                  if (gumballNum > 0) {

                      this.state = noQuarterState;

                  }

                  System.out.println("the machine has " + gumballNum + " gumball(s)");

              }

          }

          class SoldToWinnerState implements State {

              GumballMachine gm;

              public SoldToWinnerState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  System.out.println("you have insert one quarter already");

              }

              public void ejectQuarter() {

                  System.out.println("you have turn crank already");

              }

              public void turnCrank() {

                  System.out.println("you have turn crank already");

              }

              public void dispense() {

                  gm.gumballNum -= 2; //具體細節,比如機器里只有一個糖果,暫不考慮,不是重點

                  System.out.println("*************you are winner!************");

                  System.out.println("dispense two gumball...");

                  if (gm.gumballNum > 0) {

                      gm.setState(gm.noQuarterState);

                  }

                  else {

                      System.out.println("Machine has no gumball");

                      gm.setState(gm.soldOutState);

                 }

              }

          }

          class NoQuarterState implements State {

              GumballMachine gm;

              public NoQuarterState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  System.out.println("insert a quarter...");

                  gm.setState(gm.hasQuarterState);

              }

              public void ejectQuarter() {

                  System.out.println("you can't eject quarter, for you haven't insert yet 1");

              }

              public void turnCrank() {

                  System.out.println("you can't turn crank, for you haven't insert yet 2");

              }

              public void dispense() {

                  System.out.println("you can't dispense, for you haven't insert yet 3");

              }

          }

          class HasQuarterState implements State {

              Random rm;

              GumballMachine gm;

              public HasQuarterState(GumballMachine gm) {

                  this.gm = gm;

                  rm = new Random();

              }

              public void insertQuarter() {

                  System.out.println("you can't insert quarter, for you have insert one already");

              }

              public void ejectQuarter() {

                  System.out.println("eject quarter...");

                  gm.setState(gm.noQuarterState);

              }

              public void turnCrank() {

                  System.out.println("turning the crank...");

                  if (rm.nextFloat() * 10 == 9) { //產生0-9之間的隨機數

                      gm.setState(gm.soldToWinnerState);

                  }

                  else {

                      gm.setState(gm.soldState);

                  }

                  gm.state.dispense();

              }

              public void dispense() {

                  System.out.println("when you turn the crank, the machine will dispense the gumball");

              }

          }

          class SoldState implements State {

              GumballMachine gm;

              public SoldState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void ejectQuarter() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void turnCrank() {

                  throw new UnsupportedOperationException("Not supported yet.");

              }

              public void dispense() {

                  gm.gumballNum--;

                  System.out.println("dispense one gumball...");

                  if (gm.gumballNum > 0) {

                      gm.setState(gm.noQuarterState);

                  }

                  else {

                      System.out.println("Machine has no gumball");

                      gm.setState(gm.soldOutState);

                  }

              }

          }

          class SoldOutState implements State {

              GumballMachine gm;

              public SoldOutState(GumballMachine gm) {

                  this.gm = gm;

              }

              public void insertQuarter() {

                  System.out.println("you can't insert quarter, for the machine has no gumball");

              }

              public void ejectQuarter() {

                  System.out.println("you can't eject quarter, for the machine has no gumball");

              }

              public void turnCrank() {

                  System.out.println("you can't turn crank, for the machine has no gumball");

              }

              public void dispense() {

                  System.out.println("you can't dispense, for the machine has no gumball");

              }

          }


          可見,在
          state pattern中,新增一個狀態,只需要新增一個(表達這個狀態的)類,并在該狀態的“上游狀態”做少許改動即可。

          posted on 2008-07-18 00:38 化的了 閱讀(2864) 評論(8)  編輯  收藏 所屬分類: 設計模式

          Feedback

          # re: State Pattern 狀態模式 2008-07-18 08:45 melland
          都是head first design pattern上的例子呀  回復  更多評論
            

          # re: State Pattern 狀態模式 2008-07-18 09:13 Always BaNg.
          我不知道寫這種非自己原創,并且資料隨處可查的東西有什么意義?

          或許你寫State Pattern但可以加入自己在實際工程使用過程中的體會啊。

          純碎的抄襲是可恥的,不指明原處的抄襲更加可恥!


          沒有攻擊樓主的意思,是不過對于一個嚴格要求自己的程序員來說,應該做的更好一些。  回復  更多評論
            

          # re: State Pattern 狀態模式 2008-07-18 13:40 ron
          如果狀態變化不頻繁,沒有必要使用這種方式。代碼膨脹,可讀性極差!我喜歡使用表驅動。將狀態和變換方式存儲為表的橫格和豎格,將狀態處理函數指針存儲為表格的內容。如果想擴展,增加行或者列即可。
          ----------------
          老實說,你文中給的那個例子太啰嗦了。  回復  更多評論
            

          # re: State Pattern 狀態模式 2008-07-18 15:20 化的了
          @Always BaNg.
          書的確是看的《Head first desgin pattern》
          舉的例子也的確是書上的。

          但代碼是自己寫的,文字思路是自己的,UML圖是自己畫的。。。不存在抄襲的問題。只是想自己總結一下這些設計模式的思路的產生過程。

          本人還是學生,看書學習為主,項目經驗幾乎沒有,寫的不好,希望大家理解。有的東西,其實是寫給自己看的,放在網上,大家覺得好,也可以分享。覺得不好,就算了。  回復  更多評論
            

          # re: State Pattern 狀態模式 2008-07-18 15:52 Always BaNg.
          @化的了
          不好意思,如果是學生,我說的有些過分,先表示歉意。

          不過現在學校一般教的都很爛,你更應該把時間花在比如數學,操作系統,計算機原理,編譯原理,硬件相關的編程上面,設計模式的本意是在有很大量設計之后才產生的模式,即細節已不是什么大問題,全局是問題。如果計算機基礎都不牢固,空談這些模式沒什么意義,先把細節搞清楚才是王道。

          再者,多參與一些項目實踐,對自己很有好處。

          最后,祝博主學業有成!


            回復  更多評論
            

          # re: State Pattern 狀態模式 2008-07-22 14:13 Bruce Luo
          switch(month){
          case 1,3,5,7,8,10,12:
          day=31;break;
          case 4,6,9,11:
          day=30;break;
          case 2:
          day=28;break;
          }
          使用表驅動法:
          var days=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
          day=days[month-1];
            回復  更多評論
            

          # re: State Pattern 狀態模式[未登錄] 2008-12-03 14:46 aa
          這樣的爛東西不要放上來,浪費大家的時間  回復  更多評論
            

          # re: State Pattern 狀態模式 2009-03-17 16:13 zdcin
          @ron
          我深有同感,表驅動的狀態模式比這種代碼簡潔多了(只有架構代碼,數據全在表中),而且更能抽象狀態的變化流轉,更具有通用性,類實現的狀態機,架構代碼也應用代碼混淆,而且應用代碼重復(狀態有多少個就重復多少次),在應用代碼中可以任意跳轉,看代碼都能把人看暈,實在不知道GOF講設計模式時為什么不多講講類方式狀態機的弊端,以至造成類方式狀態機的泛濫。  回復  更多評論
            

          主站蜘蛛池模板: 定州市| 平武县| 大同市| 石棉县| 乾安县| 新余市| 郑州市| 崇仁县| 会同县| 南京市| 南城县| 西城区| 贡觉县| 陵川县| 嘉义市| 九江县| 浑源县| 公安县| 鄂温| 太和县| 长顺县| 吕梁市| 铜山县| 淮阳县| 思南县| 民乐县| 太仆寺旗| 乐陵市| 乐山市| 陇南市| 安达市| 潍坊市| 舟山市| 昌图县| 南昌市| 厦门市| 长春市| 拉孜县| 南岸区| 孝义市| 剑河县|