狀態模式,顧名思義,重點關注物件的各種狀態,狀態模式將物件的每一種狀態獨立成類,同時將物件的行為委托給對應的狀態類執行,它的優點在于,當需要增加或者減少物件的狀態時,只需要增加減少狀態類,并修改少量的代碼就能實作,
本文將采用狀態模式和非狀態模式分別實作同一個例子,以講解狀態模式的用法以及使用狀態模式的好處,
例子很簡單,我們想用程式來模擬人在不同負重下的行走和奔跑行為,負重越少,行走和奔跑就越輕松;負重越多行走和奔跑則愈發費勁,甚至根本就跑不動,
1. 普通方式實作人在不同負重下的行走和奔跑行為
首先采用最平常的方式來實作行走和奔跑的設計:
public class Human { private double weight; //體重 private double weightBearing; //負重 public Human(double weight){ this.weight = weight; } public void setWeightBearing(double weightBearing){ this.weightBearing = weightBearing; } public double getRate(){ return weightBearing / weight; } public void walk(){ double rate = getRate(); if(rate < 0.2){ System.out.println("輕輕松松地走,,,"); }else if(rate < 0.6){ System.out.println("氣喘吁吁地走,,,"); }else{ System.out.println("只能慢慢走,,,"); } } public void run(){ double rate = getRate(); if(rate < 0.2){ System.out.println("一路小跑,,,"); }else if(rate < 0.6){ System.out.println("象征性地跑,,,"); }else{ System.out.println("跑不動,,,"); } }}
然后測一測代碼的效果:
public class StatePatternTest { public static void main(String[] args){ StatePatternTest test = new StatePatternTest(); test.normalTest(); } public void normalTest(){ Human human = new Human(150); human.walk(); human.run(); human.setWeightBearing(50); human.walk(); human.run(); human.setWeightBearing(100); human.walk(); human.run(); }}
輸出如下:
輕輕松松地走,,,一路小跑,,,氣喘吁吁地走,,,象征性地跑,,,只能慢慢走,,,跑不動,,,代碼看起來沒有問題,不過我們發現,負重比在大于60%這個區間還可以進一步細化,因為負重越大,對體能影響越大,這個時候每增加10%可能都會有不一樣的結果,對于這樣的細化要求,我們需要修改上面每個方法里的分支陳述句,并且隨著以后的細化需求越來越多,分支會越來越長,不利于維護,
通過觀察分析,我們發現,不同的區間對應不同的行為,可以根據區間進行劃分,每個區間實作自己的walk()和fun()方法,對于Human物件來說,不需要知道現在是處在哪個負重區間,只需要將行為委托給區間物件去處理就行了,在這里,我們稱不同的區間為不同的狀態,所有的狀態實作或者繼承同一個State物件,
接下來,我們準備使用狀態模式重新實作行走和奔跑的設計,在繼續進行下去之前,先給出狀態模式的定義,
2. 狀態模式的定義
狀態模式允許物件在內部狀態改變時改變它的行為,物件看起來好像修改了它的類,
定義的第一部分說的是狀態改變的時候,物件的行為也會隨之改變,在我們的例子中,負重改變時,行走和奔跑的行為會有不同的表現;定義的第二部分是說,狀態改變的時候物件發生對應的改變,在外界看起來,好像是在跟一個新的類打交道,實際上我們知道,物件還是那個物件,只是底層的實作改變了而已,
3. 采用狀態模式的實作
下面將使用狀態模式來重新設計,首先定義統一的狀態介面State:
public interface State { void walk(); void run();}
根據不同的負重定義三種負重狀態:
//輕度負重類public class SlightlyOverWeighted implements State { private SmartHuman human; public SlightlyOverWeighted(SmartHuman human){ this.human = human; } @Override public void walk() { if(human.getRate() < 0.2){ System.out.println("輕輕松松地走,,,"); }else{ human.setState(new MiddleOverWeighted(human)); human.walk(); } } @Override public void run() { if(human.getRate() < 0.2){ System.out.println("一路小跑,,,"); }else{ human.setState(new MiddleOverWeighted(human)); human.run(); } }
}
//中度負重類public class MiddleOverWeighted implements State{ private SmartHuman human; public MiddleOverWeighted(SmartHuman human){ this.human = human; } @Override public void walk() { if(human.getRate() < 0.6){ System.out.println("氣喘吁吁地走,,,"); }else{ human.setState(new OverWeighted(human)); human.walk(); } } @Override public void run() { if(human.getRate() < 0.6){ System.out.println("象征性地跑,,,"); }else{ human.setState(new OverWeighted(human)); human.run(); } }}
//超重類public class OverWeighted implements State{ private SmartHuman human; public OverWeighted(SmartHuman human){ this.human = human; } @Override public void walk() { System.out.println("只能慢慢走,,,"); } @Override public void run() { System.out.println("跑不動,,,"); }}
下面測驗一下采用狀態模式的實作:
public class StatePatternTest { public static void main(String[] args){ StatePatternTest test = new StatePatternTest(); test.statePatternTest(); } public void statePatternTest(){ SmartHuman human = new SmartHuman(150); human.walk(); human.run(); human.setWeightBearing(50); human.walk(); human.run(); human.setWeightBearing(100); human.walk(); human.run(); }}
輸出為:
輕輕松松地走,,,一路小跑,,,氣喘吁吁地走,,,象征性地跑,,,只能慢慢走,,,跑不動,,,4. 總結
新的測驗類幾乎與之前的測驗一模一樣,而且結果也符合預期,當我們想喜歡負重狀態時,只需要增加對應的狀態類,然后修改相鄰狀態類的少量代碼即可,從上面的代碼總結出狀態模式的類圖結構如下:

5. 參考文獻
<<Head First設計模式>>
<<大話設計模式>>
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/37787.html
標籤:設計模式
下一篇:設計模式-單例模式code
