假設我們正在做一個即時戰略遊戲,我們設計一個兵種,他在剛剛生產出來的時候是步兵,但是他可以切換武器,第一次切換會變成弓箭手,第二次切換會變成舉着盾牌的裝甲兵,第三次切換則又變成了步兵……如何實現這個切換的機制?我們一開始會想到,在步兵這個類中加入switch語句,然而這樣的話,代碼不利於擴展,不利於修改,這時我們就可以使用狀態模式了。
狀態模式允許一個對象在其內部狀態改變時改變它的行爲。對象看起來似乎修改了它的類。
在本例中,這個兵種有3個狀態——步兵、弓箭手和裝甲兵。我們將這3個狀態都繼承於同一個基類SoldierState,我們還需要定義一個兵種類來包含一個SoldierState對象,以便它是用來存儲這些狀態的,在本例中這個類的名字叫做KnightContext。先看Java代碼吧:
abstract class SoldierState {
public abstract void show();
protected void changeState(KnightContext knight, SoldierState soldierState){
knight.changeState(soldierState);
}
public abstract void transform(KnightContext knight);
}
class KnightContext {
SoldierState state;
public KnightContext(){
state = SwordState.getState();
}
public void changeState(SoldierState state){
this.state = state;
state.show();
}
public void transform(){
state.transform(this);
}
}
class SwordState extends SoldierState{
private static SoldierState state = new SwordState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("現在是步兵模式。");
}
public void transform(KnightContext knight) {
changeState(knight, BowState.getState());
}
}
class BowState extends SoldierState{
private static SoldierState state = new BowState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("現在是弓箭模式。");
}
public void transform(KnightContext knight) {
changeState(knight, ShieldState.getState());
}
}
class ShieldState extends SoldierState{
private static SoldierState state = new ShieldState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("現在是盾牌模式。");
}
public void transform(KnightContext knight) {
changeState(knight, SwordState.getState());
}
}
public class State
{
public static void main(String[] args) {
KnightContext knight = new KnightContext();
knight.transform();
knight.transform();
knight.transform();
knight.transform();
knight.transform();
}
SwordState、BowState、ShieldState爲此兵種的三個狀態。KnightContext中有個SoldierState類型的成員state表示這個兵種的當前狀態。請注意,我們並不希望把如何切換的過程寫在KnightContext中(一般的想法可能是,在changeState中加入switch塊,這樣會使得KnightContext過於繁重),而是把如何轉換寫在了SoldierState的transform方法中。這樣就避免了在KnightContext中加入大量的切換狀態的代碼。如果需要新增加一個狀態,只需要修改和增加SoldierState的子類即可。對於每一個狀態,它都有一個單獨的子類來表示,因此在狀態多的情況下會出現很多個子類,這也是狀態模式的缺點。
程序運行的結果爲:
現在是弓箭模式。
現在是盾牌模式。
現在是步兵模式。
現在是弓箭模式。
現在是盾牌模式。
以上便是狀態模式的說明,希望能夠對大家有所幫助。