posts - 5,comments - 14,trackbacks - 0
          前天朋友蛋殼老兄推薦了這篇文章給我,挺好玩的。
          挺喜歡里面的挨打、小宇宙爆發情節,相信圣斗士的fans都會喜歡,特此轉載。
          來源:http://www.javaeye.com/topic/212142

          星矢:動畫片《圣斗士星矢》的男豬腳,超級小強,怎么打也打不死。
          雅典娜:動畫片《圣斗士星矢》的女豬腳,自稱女神,手下有88個男人為他賣命。
          狀態模式:為了方便的控制狀態的變化,避免一堆IF/ELSE,以及狀態規則改變的時避免代碼改動的混亂。
          觀察者模式:一個被觀察者一動,多個觀察者跟著動,經常用于界面UI。

          話說星矢和很強的某斗士甲對打,雅典娜在一邊看,星矢總是挨揍,每次挨揍完之后星矢的狀態總是會發生一些變化:

          正常--挨打--瀕死--挨打--小宇宙爆發--挨打--瀕死--挨打--女神護體--挨打(星矢無敵了,打也沒用,戰斗結束)--正常

          以上狀態轉變用狀態模式來表現,一個Saiya類代表星矢,一個SaiyaState代表他的狀態,SaiyaState下面有多個子類,分別代表星矢的多種狀態,如正常NORMAL、瀕死DYING、小宇宙爆發UNIVERSE、女神護體GODDESS,即把狀態抽象成對象,在每種狀態里面實現被打的時候所需要更改的狀態,這樣就避免了每次被打都要進行一次IF/ELSE的判斷。

          Java代碼 復制代碼
          1. public class Saiya extends Observable {   
          2.     //定義星矢的四種狀態   
          3.     public final SaiyaState NORMAL = new NormalState(this);   
          4.   
          5.     public final SaiyaState DYING = new DyingState(this);   
          6.   
          7.     public final SaiyaState GODDESS = new GoddessState(this);   
          8.   
          9.     public final SaiyaState UNIVERSE = new UniverseState(this);   
          10.        
          11.     private SaiyaState state=NORMAL;   
          12.        
          13.     private SaiyaState laststate=null;   
          14.        
          15.     public void hit(){   
          16.         //調用當前狀態的被打方法 反過來改變自己的狀態   
          17.         state.hit();   
          18.     }   
          19.     public String status(){   
          20.         //當前狀態名   
          21.         return state.status();   
          22.     }   
          23.        
          24.     protected void setState(SaiyaState state){   
          25.         laststate=this.state;   
          26.         this.state=state;   
          27.         //觀察者模式   
          28.         setChanged();   
          29.         notifyObservers("星矢狀態變化");   
          30.     }   
          31.        
          32.     public String getlastStatus(){   
          33.         return laststate.status();   
          34.     }  

          星矢的狀態
          Java代碼 復制代碼
          1. public abstract class SaiyaState {   
          2.     protected Saiya saiya;   
          3.   
          4.     public SaiyaState(Saiya saiya) {   
          5.         this.saiya = saiya;   
          6.     }   
          7.        
          8.     public String status(){   
          9.         String name=getClass().getName();   
          10.         return name.substring(name.lastIndexOf(".")+1);   
          11.     }   
          12.     //星矢被打了   
          13.     public abstract void hit();   
          14. }  

          在每種狀態里面實現被打的時候所需要更改的狀態,例如小宇宙爆發狀態下被打
          Java代碼 復制代碼
          1. public class UniverseState extends SaiyaState {   
          2.   
          3.     /**  
          4.      * @param saiya  
          5.      */  
          6.     public UniverseState(Saiya saiya) {   
          7.         super(saiya);   
          8.   
          9.     }   
          10.   
          11.     /* 小宇宙爆發狀態被打進入瀕死狀態  
          12.      *   
          13.      */  
          14.   
          15.     public void hit() {   
          16.         saiya.setState( saiya.DYING);   
          17.   
          18.     }   
          19.   
          20. }  


          雅典娜在一邊看,星矢每次被打她都要給星矢加油,她是個觀察者,星矢是被觀察者,這里星矢實現java.util.Observable,每次被打hit就notifyObservers,雅典娜就加油。
          Java代碼 復制代碼
          1. public class Athena implements Observer {   
          2.   
          3.     /* 我是雅典娜 我是觀察者  
          4.      *   
          5.      */  
          6.     public void update(Observable arg0, Object arg1) {   
          7.         System.out.println("雅典娜說:星矢加油啊!!!");   
          8.         }   
          9.   
          10. }  

          總的來看 這個過程就是這樣子:
          Java代碼 復制代碼
          1. public class StateMain {   
          2.     public static void main(String[] args) {   
          3.   
          4.         Saiya saiya = new Saiya();   
          5.         Observer athena = new Athena();   
          6.         saiya.addObserver(athena);   
          7.         System.out.println("星矢最初的狀態是:" + saiya.status());   
          8.         for (int i = 0; i < 5; i++) {   
          9.             System.out.println("星矢被揍了" + (i + 1) + "次");   
          10.             saiya.hit();   
          11.             System.out.println("星矢現在的狀態是:" + saiya.status());   
          12.         }   
          13.     }   
          14. }  


          結果星矢在雅典娜的幫助下,有驚無險的戰勝了很強的某斗士甲:

          Java代碼 復制代碼
          1. 星矢最初的狀態是:NormalState   
          2. 星矢被揍了1次   
          3. 雅典娜說:星矢加油啊!!!   
          4. 星矢現在的狀態是:DyingState   
          5. 星矢被揍了2次   
          6. 雅典娜說:星矢加油啊!!!   
          7. 星矢現在的狀態是:UniverseState   
          8. 星矢被揍了3次   
          9. 雅典娜說:星矢加油啊!!!   
          10. 星矢現在的狀態是:DyingState   
          11. 星矢被揍了4次   
          12. 雅典娜說:星矢加油啊!!!   
          13. 星矢現在的狀態是:GoddessState   
          14. 星矢被揍了5次   
          15. 雅典娜說:星矢加油啊!!!   
          16. 星矢現在的狀態是:NormalState  


          總結:狀態模式的缺點就是會弄出很多子類,如果狀態沒那么復雜,狀態規則改變的可能性比較小的話就不要用了
          posted on 2008-07-09 14:54 kenlee14 閱讀(1626) 評論(10)  編輯  收藏

          FeedBack:
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-09 16:26 | lyazure
          Saiya類的setState里調用的setChanged方法哪里來的……我覺得簡單的情況下用枚舉更好  回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-09 17:04 | javaread.com
          setChanged是Observable類的方法。
          java.util.Observable中有兩個方法對Observer特別重要,一個是setChange()方法用來設置一個內部標志位注明數據發生了變化;一個是notifyObservers()方法會去調用一個列表中所有的Observer的update()方法,通知它們數據發生了變化。

          更多更詳細請參考:
          http://www.javaread.com/question/show/119  回復  更多評論
            
          # http://www.aygfsteel.com
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-09 17:50 | 隔葉黃鶯
          可惜你寫的這個系列,我完全不知道
          圣斗士星矢
          是什么東西,所以沒法看。  回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-09 23:21 | 化的了
          正常--挨打--瀕死--挨打--小宇宙爆發--挨打--瀕死--挨打--女神護體--挨打(星矢無敵了,打也沒用,戰斗結束)--正常

            回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-22 15:24 | young_suse
          從你運行結果來看,狀態的變化是:NormalState--DyingState--UniverseState--DyingState--GoddessState--NormalState
          其中DyingState出現了兩次,第一次DyingState狀態過后進入UniverseState狀態,第二次DyingState狀態過后卻進入GoddessState,不知道你的DyingState類是怎么寫的,是不是在hit()方法中做了if-else判斷的?這樣的話可就沒有達到替換if-else的目的哦!真希望樓主能把UniverseState類的代碼貼出來。

            回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-22 15:25 | young_suse
          不好意思,是把DyingState類的代碼貼出來!  回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-25 12:53 | fagacity
          可惜你寫的這個系列,我完全不知道
          圣斗士星矢
          是什么東西,所以沒法看。


          似乎不影響對狀態模式和觀察者模式 的理解吧!
            回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-28 15:46 | think4v
          @young_suse
          這個貌似是從javaeye上抄的。。。
          和那個上面的一樣  回復  更多評論
            
          # re: 圣斗士星矢的狀態模式和觀察者模式
          2008-07-28 16:09 | 風清揚
          樓上的,文章一開頭就說明是轉載的啦。
          轉載地址都貼著啦。
          暈!!!
            回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 江门市| 浦东新区| 昭平县| 绥阳县| 万年县| 文水县| 荆门市| 金平| 西充县| 葵青区| 塔河县| 弋阳县| 余干县| 高安市| 孟津县| 贺州市| 辉县市| 闵行区| 扶余县| 靖江市| 克拉玛依市| 利辛县| 乌苏市| 久治县| 开封市| 芷江| 桓台县| 玛纳斯县| 大关县| 克什克腾旗| 本溪市| 岳阳县| 延长县| 巴林左旗| 兴文县| 五家渠市| 车致| 无极县| 南昌市| 怀宁县| 漳州市|