1 概述
狀態模式(state Pattern)是行爲模式之一,一般用在對象的行爲依賴於內部狀態的場景。
2 狀態模式
考慮一個場景:對象有狀態,而且根據狀態不同,對象的行爲也會不同。對於該情況,最簡單的方式是,對狀態做if-else
或者swith-case
判斷,根據狀態調用相應的行爲。但是這種做法,把對象和狀態耦合在了一起,難於擴展和維護。更好的做法是,用狀態模式將狀態抽離出來形成一個接口,而目標對象依賴該狀態接口,來完成對應的行爲,由此達到解耦的目的。
狀態模式跟策略模式非常相像,可視爲策略模式的擴展。兩者都基於組合機制,通過將部分工作委派給另外的對象來改變其在不同情景下的行爲。不同的是,策略模式中這些對象相互之間完全獨立,不知道彼此的存在。但狀態模式沒有限制具體狀態之間的依賴,且允許它們自行改變在不同情景下的狀態。
3 案例
結合例子,來進一步理解狀態模式。
一個人的戰鬥力,在飢餓狀態和發怒狀態下是不同的,所以“戰鬥的行爲”依賴於“身體的狀態”,最簡單的做法如下:
public class Fighter {
private String mode = "normal";
public void setMode(String mode) {
this.mode = mode;
}
public void fight() {
if (mode.equalsIgnoreCase("angry")) {
System.out.println("Fighting with power 200 on angry mode!!!");
}
else if (mode.equalsIgnoreCase("hungry")) {
System.out.println("Fighting with power 50 on mode hungry...");
}
else {
System.out.println("Fighting with power 100 normal mode!");
}
}
}
簡單的if-else
塊,根據狀態控制行爲。但是這種寫法不容易維護,每當狀態需要修改/新增/刪除,都需要改動Fighter
類;而且當狀態越來越多的時候,方法體會變得越來越龐大,可讀性很低。下面看看用狀態模式如何操作:
public interface State {
void fight();
}
public class NormalState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 100 normal mode!");
}
}
public class HungryState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 50 on mode hungry...");
}
}
public class AngryState implements State {
@Override
public void fight() {
System.out.println("Fighting with power 200 on angry mode!!!");
}
}
public class Fighter implements State {
private State state = new NormalState();
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
@Override
public void fight() {
state.fight();
}
}
public class Test {
public static void main(String[] args) {
Fighter luffy = new Fighter();
State hungryState = new HungryState();
State angryState = new AngryState();
luffy.fight();
luffy.setState(hungryState);
luffy.fight();
luffy.setState(angryState);
luffy.fight();
}
}
輸出:
Fighting with power 100 normal mode!
Fighting with power 50 on mode hungry...
Fighting with power 200 on angry mode!!!
我們將“狀態”從對象中抽離出來,做成一個單獨的接口State
,並將對象的行爲放到State
的實現類中。這種模式,無論是擴展性還是可維護性,都高於前面那種方式,這就是狀態模式的威力。
4 總結
狀態模式使得對象與其狀態分離解耦,使得代碼邏輯更加靈活健壯。當對象的行爲依賴於內部狀態時,不要一昧地用if-else
,可以考慮使用狀態模式。