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 阅读(1608) 评论(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.blogjava.net
# 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 | 风清扬
楼上的,文章一开头就说明是转载的啦。
转载地址都贴着啦。
晕!!!
  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问