設計模式之狀態模式

一、定義

允許一個對象內部狀態改變時改變它的行爲。對象看起來似乎修改了它的類。
意思是一個對象可能有多重狀態,我們平時都是用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、狀態模式的本質

           根據狀態來分離和選擇行爲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章