论坛首页 Java版 设计模式

圣斗士星矢的状态模式和观察者模式

浏览 1706 次
精华帖 (0) :: 良好帖 (5) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2008-07-06
星矢:动画片《圣斗士星矢》的男猪脚,超级小强,怎么打也打不死。
雅典娜:动画片《圣斗士星矢》的女猪脚,自称女神,手下有88个男人为他卖命。
状态模式:为了方便的控制状态的变化,避免一堆IF/ELSE,以及状态规则改变的时避免代码改动的混乱。
观察者模式:一个被观察者一动,多个观察者跟着动,经常用于界面UI。

话说星矢和很强的某斗士甲对打,雅典娜在一边看,星矢总是挨揍,每次挨揍完之后星矢的状态总是会发生一些变化:

正常--挨打--瀕死--挨打--小宇宙爆发--挨打--瀕死--挨打--女神护体--挨打(星矢无敌了,打也没用,战斗结束)--正常

以上状态转变用状态模式来表现,一个Saiya类代表星矢,一个SaiyaState代表他的状态,SaiyaState下面有多个子类,分别代表星矢的多种状态,如正常NORMAL、瀕死DYING、小宇宙爆发UNIVERSE、女神护体GODDESS,即把状态抽象成对象,在每种状态里面实现被打的时候所需要更改的状态,这样就避免了每次被打都要进行一次IF/ELSE的判断。

public class Saiya extends Observable {
	//定义星矢的四种状态
	public final SaiyaState NORMAL = new NormalState(this);

	public final SaiyaState DYING = new DyingState(this);

	public final SaiyaState GODDESS = new GoddessState(this);

	public final SaiyaState UNIVERSE = new UniverseState(this);
	
	private SaiyaState state=NORMAL;
	
	private SaiyaState laststate=null;
	
	public void hit(){
		//调用当前状态的被打方法 反过来改变自己的状态
		state.hit();
	}
	public String status(){
		//当前状态名
		return state.status();
	}
	
	protected void setState(SaiyaState state){
		laststate=this.state;
		this.state=state;
		//观察者模式
		setChanged();
		notifyObservers("星矢状态变化");
	}
	
	public String getlastStatus(){
		return laststate.status();
	}

星矢的状态
public abstract class SaiyaState {
	protected Saiya saiya;

	public SaiyaState(Saiya saiya) {
		this.saiya = saiya;
	}
	
	public String status(){
		String name=getClass().getName();
		return name.substring(name.lastIndexOf(".")+1);
	}
	//星矢被打了
	public abstract void hit();
}

在每种状态里面实现被打的时候所需要更改的状态,例如小宇宙爆发状态下被打
public class UniverseState extends SaiyaState {

	/**
	 * @param saiya
	 */
	public UniverseState(Saiya saiya) {
		super(saiya);

	}

	/* 小宇宙爆发状态被打进入瀕死状态
	 * 
	 */

	public void hit() {
		saiya.setState( saiya.DYING);

	}

}


雅典娜在一边看,星矢每次被打她都要给星矢加油,她是个观察者,星矢是被观察者,这里星矢实现java.util.Observable,每次被打hit就notifyObservers,雅典娜就加油。
public class Athena implements Observer {

	/* 我是雅典娜 我是观察者
	 * 
	 */
	public void update(Observable arg0, Object arg1) {
		System.out.println("雅典娜说:星矢加油啊!!!");
		}

}

总的来看 这个过程就是这样子:
public class StateMain {
	public static void main(String[] args) {

		Saiya saiya = new Saiya();
		Observer athena = new Athena();
		saiya.addObserver(athena);
		System.out.println("星矢最初的状态是:" + saiya.status());
		for (int i = 0; i < 5; i++) {
			System.out.println("星矢被揍了" + (i + 1) + "次");
			saiya.hit();
			System.out.println("星矢现在的状态是:" + saiya.status());
		}
	}
}



结果星矢在雅典娜的帮助下,有惊无险的战胜了很强的某斗士甲:

星矢最初的状态是:NormalState
星矢被揍了1次
雅典娜说:星矢加油啊!!!
星矢现在的状态是:DyingState
星矢被揍了2次
雅典娜说:星矢加油啊!!!
星矢现在的状态是:UniverseState
星矢被揍了3次
雅典娜说:星矢加油啊!!!
星矢现在的状态是:DyingState
星矢被揍了4次
雅典娜说:星矢加油啊!!!
星矢现在的状态是:GoddessState
星矢被揍了5次
雅典娜说:星矢加油啊!!!
星矢现在的状态是:NormalState


总结:状态模式的缺点就是会弄出很多子类,如果状态没那么复杂,状态规则改变的可能性比较小的话就不要用了
   
最后更新时间:2008-07-07
呃,长见识了,原来java里面有Observer这种东西。这个东西和EventListener是个什么关系呢?啥时候用哪一种?
   
0 请登录后投票
最后更新时间:2008-07-07
这个猛的……敬佩敬佩……
   
0 请登录后投票
最后更新时间:2008-07-07
Nighthaven 写道
呃,长见识了,原来java里面有Observer这种东西。这个东西和EventListener是个什么关系呢?啥时候用哪一种?


观察者模式由于在界面UI用的比较多,JDK就实现好了java.util.Observer和java.util.Observable,需要的时候直接拿来用就行,EventListener没用过。
   
0 请登录后投票
最后更新时间:2008-07-07
Nighthaven 写道
呃,长见识了,原来java里面有Observer这种东西。这个东西和EventListener是个什么关系呢?啥时候用哪一种?


Observer是模式,不是说java里有这种模式,而是此模式能适用于java语言
   
0 请登录后投票
最后更新时间:2008-07-07
关于Java里面Observer模式和EventListener的区别下面这篇文章说的很清楚

http://www.javaeye.com/topic/182643
   
0 请登录后投票
最后更新时间:2008-07-07
涨见识了,原来星矢还可以这么玩儿。以后如果记不清Observer,想想星矢就可以了,谢谢楼主的创意。

希望漫画迷们多多出些这样的例子,比较容易记忆。
   
0 请登录后投票
最后更新时间:2008-07-07
长见识了~~

把动画片和模式联系起来~  楼主的创意太好了~  值得学习!!!
   
0 请登录后投票
最后更新时间:2008-07-17
java 提供的观察者模式用的是继承。

public class Saiya extends Observable { 

其实还是有些坏处的。

所以用的时候还是要小心一些的。
   
0 请登录后投票
最后更新时间:2008-08-12
补充上DyingState类:

public class DyingState extends SaiyaState{

	public DyingState(Saiya saiya) {   
        super(saiya);   
  
    }   

  
    public void hit() {   
        //是普通状态下被打成瀕死状态时 会变成小宇宙爆发状态
    	if (saiya.getlastStatus().equals("NormalState")) {
        saiya.setState( saiya.UNIVERSE);   
        //是小宇宙爆发状态下被打成瀕死状态时 会变成女神副体状态
    	}else if(saiya.getlastStatus().equals("UniverseState")){
        saiya.setState( saiya.GODDESS);
    	}
    } 
}
   
0 请登录后投票
论坛首页 Java版 设计模式

跳转论坛:
JavaEye推荐