小A:“講了那麼多,師兄如果能給我舉個例子那就更好了。”
大B:“那我給你舉個聖鬥士星矢的狀態模式和觀察者模式的例子吧!”
星矢:動畫片《聖鬥士星矢》的男豬蹄,超級小強,怎麼打也打不死。
雅典娜:動畫片《聖鬥士星矢》的女豬蹄,自稱女神,手下有88個男人為他賣命。
狀態模式:為了方便的控制狀態的變化,避免一堆IF/ELSE,以及狀態規則改變的時避免程式碼改動的混亂。
觀察者模式:一個被觀察者一動,多個觀察者跟著動,經常用於介面UI。
話說星矢和很強的某鬥士甲對打,雅典娜在一邊看,星矢總是捱揍,每次捱揍完之後星矢的狀態總是會發生一些變化:
正常——捱打——瀕死——捱打——小宇宙爆發——捱打——瀕死——捱打——女神護體——捱打(星矢無敵了,打也沒用,戰鬥結束)——正常
以上狀態轉變用狀態模式來表現,一個Saiya類代表星矢,一個SaiyaState代表他的狀態,SaiyaState下面有多個子類,分別代表星矢的多種狀態,如正常NORMAL、瀕死DYING、小宇宙爆發UNIVERSE、女神護體GODDESS,即把狀態抽象成物件,在每種狀態裡面實現被打的時候所需要更改的狀態,這樣就避免了每次被打都要進行一次IF/ELSE的判斷。
Java程式碼
publicclassSaiyaextendsObservable{
//定義星矢的四種狀態
publicfinalSaiyaStateNORMAL=newNormalState(this);
publicfinalSaiyaStateDYING=newDyingState(this);
publicfinalSaiyaStateGODDESS=newGoddessState(this);
publicfinalSaiyaStateUNIVERSE=newUniverseState(this);
privateSaiyaStatestate=NORMAL;
privateSaiyaStatelaststate=null;
publicvoidhit(){
//呼叫當前狀態的被打方法?反過來改變自己的狀態
state.hit();
}
publicStringstatus(){
//當前狀態名
returnstate.status();
}
protectedvoidsetState(SaiyaStatestate){
laststate=this.state;
this.state=state;
//觀察者模式
setChanged();
notifyObservers(“星矢狀態變化”);
}
publicStringgetlastStatus(){
returnlaststate.status();
}
publicclassSaiyaextendsObservable{
//定義星矢的四種狀態
publicfinalSaiyaStateNORMAL=newNormalState(this);
publicfinalSaiyaStateDYING=newDyingState(this);
publicfinalSaiyaStateGODDESS=newGoddessState(this);
publicfinalSaiyaStateUNIVERSE=newUniverseState(this);
privateSaiyaStatestate=NORMAL;
privateSaiyaStatelaststate=null;
publicvoidhit(){
//呼叫當前狀態的被打方法反過來改變自己的狀態
state.hit();
}
publicStringstatus(){
//當前狀態名
returnstate.status();
}
protectedvoidsetState(SaiyaStatestate){
laststate=this.state;
this.state=state;
//觀察者模式
setChanged();
notifyObservers(“星矢狀態變化”);
}
publicStringgetlastStatus(){
returnlaststate.status();
}
星矢的狀態
Java程式碼
publicabstractclassSaiyaState{
protectedSaiyasaiya;
publicSaiyaState(Saiyasaiya){
this.saiya=saiya;
}
publicStringstatus(){
Stringname=getClass().getName();
returnname.substring(name.lastIndexOf()+1);
}
//星矢被打了
publicabstractvoidhit();
}
publicabstractclassSaiyaState{
protectedSaiyasaiya;
publicSaiyaState(Saiyasaiya){
this.saiya=saiya;
}
publicStringstatus(){
Stringname=getClass().getName();
returnname.substring(name.lastIndexOf()+1);
}
//星矢被打了
publicabstractvoidhit();
}
在每種狀態裡面實現被打的時候所需要更改的狀態,例如小宇宙爆發狀態下被打Java程式碼
publicclassUniverseStateextendsSaiyaState{
/**
*@paramsaiya
*/
publicUniverseState(Saiyasaiya){
super(saiya);
}
/*小宇宙爆發狀態被打進入瀕死狀態
*
*/
publicvoidhit(){
saiya.setState(saiya.DYING);
}
}
publicclassUniverseStateextendsSaiyaState{
/**
*@paramsaiya
*/
publicUniverseState(Saiyasaiya){
super(saiya);
}
/*小宇宙爆發狀態被打進入瀕死狀態
*
*/
publicvoidhit(){
saiya.setState(saiya.DYING);
}
}
雅典娜在一邊看,星矢每次被打她都要給星矢加油,她是個觀察者,星矢是被觀察者,這裡星矢實現java.util.Observable,每次被打hit就notifyObservers,雅典娜就加油。
Java程式碼
publicclassAthenaimplementsObserver{
/*我是雅典娜我是觀察者
*
*/
publicvoidupdate(Observablearg0,Objectarg1){
System.out.println(“雅典娜說:星矢加油啊!”);
}
}
publicclassAthenaimplementsObserver{
/*我是雅典娜我是觀察者
*
*/
publicvoidupdate(Observablearg0,Objectarg1){
System.out.println(“雅典娜說:星矢加油啊!”);
}
}
總的來看這個過程就是這樣子:
Java程式碼
publicclassStateMain{
publicstaticvoidmain(String[]args){
Saiyasaiya=newSaiya();
Observerathena=newAthena();
saiya.addObserver(athena);
System.out.println(星矢最初的狀態是:+saiya.status());
for(inti=0;i