书城计算机大话设计模式
11030400000070

第70章 11 圣斗士星矢的状态模式和观察者模式

小A:“讲了那么多,师兄如果能给我举个例子那就更好了。”

大B:“那我给你举个圣斗士星矢的状态模式和观察者模式的例子吧!”

星矢:动画片《圣斗士星矢》的男猪蹄,超级小强,怎么打也打不死。

雅典娜:动画片《圣斗士星矢》的女猪蹄,自称女神,手下有88个男人为他卖命。

状态模式:为了方便的控制状态的变化,避免一堆IF/ELSE,以及状态规则改变的时避免代码改动的混乱。

观察者模式:一个被观察者一动,多个观察者跟着动,经常用于界面UI。

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

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

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

Java代码

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 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();

}

星矢的状态

Java代码

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 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();

}

在每种状态里面实现被打的时候所需要更改的状态,例如小宇宙爆发状态下被打Java代码

public class UniverseState extends SaiyaState{

/ *@param saiya

*/

public UniverseState(Saiya saiya){

super(saiya);

}

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

*

*/

public void hit(){

saiya。setState(saiya。DYING);

}

}

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,雅典娜就加油。

Java代码

public class Athena implements Observer{

/*我是雅典娜 我是观察者

*

*/

public void update(Observable arg0,Object arg1){

System。out。println(“雅典娜说:星矢加油啊!”);

}

}

public class Athena implements Observer{

/*我是雅典娜 我是观察者

*

*/

public void update(Observable arg0,Object arg1){

System。out。println(“雅典娜说:星矢加油啊!”);

}

}

总的来看这个过程就是这样子:

Java代码

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());

}

}

}

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());

}

}

}

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

Java代码

星矢最初的状态是:NormalState

星矢被揍了1次

雅典娜说:星矢加油啊!

星矢现在的状态是:DyingState

星矢被揍了2次

雅典娜说:星矢加油啊!

星矢现在的状态是:UniverseState

星矢被揍了3次

雅典娜说:星矢加油啊!

星矢现在的状态是:DyingState

星矢被揍了4次

雅典娜说:星矢加油啊!

星矢现在的状态是:GoddessState

星矢被揍了5次

雅典娜说:星矢加油啊!

星矢现在的状态是:NormalState

星矢最初的状态是:NormalState

星矢被揍了1次

雅典娜说:星矢加油啊!

星矢现在的状态是:DyingState

星矢被揍了2次

雅典娜说:星矢加油啊!

星矢现在的状态是:UniverseState

星矢被揍了3次

雅典娜说:星矢加油啊!

星矢现在的状态是:DyingState

星矢被揍了4次

雅典娜说:星矢加油啊!

星矢现在的状态是:GoddessState

星矢被揍了5次

雅典娜说:星矢加油啊!

星矢现在的状态是:NormalState

总结:状态模式的缺点就是会弄出很多子类,如果状态没那么复杂,状态规则改变的可能性比较小的话就不要用了。