一、定义
允许一个对象内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
意思是一个对象可能有多重状态,我们平时都是用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、状态模式的本质
根据状态来分离和选择行为