一、定義
允許一個對象內部狀態改變時改變它的行爲。對象看起來似乎修改了它的類。
意思是一個對象可能有多重狀態,我們平時都是用if-else來分開狀態,根據不同的狀態來調用不同的行爲方法。二、舉例說明
我個人不喜歡玩其他的遊戲,就喜歡玩Dota。那我就用dota中的殺人稱號來舉例說明。事先聲明,在這裏我說的都是短期內殺人,當你殺死第一個人的時候是First Blood,第二個人是Double Kill,三個人是Triple Kill,殺人數達到8個 M-m-m-m…Monster Kill ,殺人數達到9個 Godlike ,殺人數達到10個 Holy Shit。中間的大於3個且小於8個的不多說了,爲了少弄幾個類,就叫牛逼吧。
如果讓我們編程的話,沒有學過設計模式的同學可能會這樣來寫程序。
public String KillName(int killCount){
String killName = null;
if(killCount==1){
killName = "First Blood";
}else if(killCount==2){
killName = "Double Kill";
}
else if(killCount==3){
killName = "Triple Kill";
}
else if(killCount>3 && killCount<8){
killName = "牛逼";
}
else if(killCount==8){
killName = "M-m-m-m…Monster Kill";
}
else if(killCount==9){
killName = "Godlike";
}
else if(killCount==10){
killName = "Holy Shit";
}
return killName;
}
問題是什麼呢?
1、如果killCount有1000種叫法,那麼就得寫1000個if
2、如果每種狀態處理的業務比較多的話,就會造成類非常的龐大
2、如果有新的狀態的話,我們還得繼續添加if-else。
爲了解決這些問題我們可以採用狀態模式。
狀態模式的類圖:
三、代碼說明
KillNameManager類 上下文
public class KillNameManager {
private Map<String,Integer> mapKillCount = new HashMap<String, Integer>();
private Map<String,KillState> mapKillState = new HashMap<String, KillState>();
public Map<String, Integer> getMapKillCount() {
return mapKillCount;
}
public void setMapKillCount(Map<String, Integer> mapKillCount) {
this.mapKillCount = mapKillCount;
}
public Map<String, KillState> getMapKillState() {
return mapKillState;
}
public void setMapKillState(Map<String, KillState> mapKillState) {
this.mapKillState = mapKillState;
}
public String killPeople(String player){
Integer killCount = mapKillCount.get(player);
if(null == killCount){
killCount = 0;
}
killCount++;
mapKillCount.put(player, killCount);
KillState killState = mapKillState.get(player);
if(killState==null){
killState = new KillFirstPeopleState();
mapKillState.put(player, killState);
}
return killState.killPeople(player, this);
}
//1、把不同的處理業務封裝在不同的狀態中,這樣Manager上下文的類就簡化了,不會變的龐大
//2、把邏輯業務放在狀態中了,這樣我們就可以繼續擴展下去。
//3、我們不用修改Manager中的代碼,只要實現KillState繼續寫狀態就行
/*public String KillName(int killCount){
String killName = null;
if(killCount==1){
killName = "First Blood";
}else if(killCount==2){
killName = "Double Kill";
}
else if(killCount==3){
killName = "Triple Kill";
}
else if(killCount>3 && killCount<8){
killName = "牛逼";
}
else if(killCount==8){
killName = "M-m-m-m…Monster Kill";
}
else if(killCount==9){
killName = "Godlike";
}
else if(killCount==10){
killName = "Holy Shit";
}
return killName;
}*/
}
狀態接口:
public interface KillState {
String killPeople(String player,KillNameManager nameManager);
}
Client 類
public class Player {
private static String playerName = "小呂布";
/**
* @param args
*/
public static void main(String[] args) {
KillNameManager nameManager = new KillNameManager();
for(int i=0;i<10;i++){
String killName = nameManager.killPeople(playerName);
System.out.println(killName);
}
}
}
具體的狀態類:
public class KillFirstPeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "First Blood";
if(nameManager.getMapKillCount().get(player)>0){
nameManager.getMapKillState().put(player, new KillSecondPeopleState());
}
return killName;
}
}
public class KillSecondPeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "Double Kill";
if(nameManager.getMapKillCount().get(player)>=2){
nameManager.getMapKillState().put(player, new KillThreePeopleState());
}
return killName;
}
}
public class KillThreePeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "Triple Kill";
if(nameManager.getMapKillCount().get(player)>=3 && nameManager.getMapKillCount().get(player)<8){
nameManager.getMapKillState().put(player, new KillLotofState());
}
return killName;
}
}
public class KillLotofState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "牛逼";
if(nameManager.getMapKillCount().get(player)==8){
nameManager.getMapKillState().put(player, new KillEightPeopleState());
}
return killName;
}
}
public class KillEightPeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "M-m-m-m…Monster Kill";
if(nameManager.getMapKillCount().get(player)>=8){
nameManager.getMapKillState().put(player, new KillNinePeopleState());
}
return killName;
}
}
public class KillNinePeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "Godlike";
if(nameManager.getMapKillCount().get(player)>=9){
nameManager.getMapKillState().put(player, new KillTenPeopleState());
}
return killName;
}
}
public class KillTenPeopleState implements KillState {
@Override
public String killPeople(String player, KillNameManager nameManager) {
String killName = "Holy Shit";
return killName;
}
}
運行結果:
這個例子的類圖是:
前面的狀態對後面的狀態有依賴關係。
四、總結
1、狀態模式的優缺點
優點:
簡化應用邏輯控制:狀態模式使用單獨的類來封裝一個狀態的處理。如果把一個大的程序控制分成很多小塊,每塊定義一個狀態來代表,那麼就可以把這些邏輯控制的代碼分散到很多單獨的狀態類中去,這樣就把着眼從執行狀態提高到整個對象的狀態,使得代碼結構和意圖更清晰,從而簡化應用的邏輯控制。
更好的分離狀態和行爲:狀態模式通過設置所有狀態類的公共接口,把狀態和狀態對應的行爲分離開,把所有與一個特定的狀態相關的行爲都放入一個對象中,使得應用程序在控制的時候,只需要關心狀態的切換,而不用關心這個狀態對應的真正處理。
更好的擴展性:引入了狀態處理的公共接口後,使得擴展新的狀態變的非常的容易,只需要增加一個實現狀態處理的公共接口的實現類,然後在運行狀態維護的地方,設置狀態變化到這個新的狀態即可。
缺點:
就是每一個狀態對應一個狀態類,這樣會導致有衆多的狀態類,會使得程序變的混亂。
2、狀態模式的本質
根據狀態來分離和選擇行爲