状态模式的定义是:当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了自身所属的类。
该模式适合于对象具有有限的状态,并且在状态之间相互切换。
例如使用如下的条件分支语句也是属于状态的切换:
switch (action){ case "play": state="playing"; break; case "stop": state="stopping"; break;
}
当后期状态增多和状态转换复杂之后,使用这种方式会对后续的维护增加困难。使用状态模式能有效解决这种维护的困难,通过将与状态相关的行为抽取到独立的状态类中, 让原对象将工作委派给这些类的实例, 而不是自行进行处理,将复杂度隔离在状态类中。
该模式中存在 3 类对象:
- Context 上下文:保持有状态类的引用
- State 抽象状态:定义状态的方法
- ConcreteState 具体状态
代码实现:
//抽象状态
public abstract class State { protected Player player; public State(Player player) { this.player = player; } // 停止 public abstract void onStop(); // 播放 public abstract void onPlay();
}
//具体状态:停止状态
public class StoppingState extends State{ public StoppingState(Player player) { super(player); } @Override public void onStop() { System.out.println("已经停止"); } @Override public void onPlay() { player.setState(new PlayingState(player)); player.setPlaying(true); }
}// 具体状态:播放状态
public class PlayingState extends State { public PlayingState(Player player) { super(player); } @Override public void onStop() { player.setState(new StoppingState(player)); player.setPlaying(false); } @Override public void onPlay() { System.out.println("已经在播放"); }
}
//上下文对象
@Data
public class Player { private State state; private boolean playing;
}
Player player=new Player();
//设置初始状态
player.setState(new StoppingState(player));
//播放
player.getState().onPlay();
System.out.println(player.getState());
//停止
player.getState().onStop();
System.out.println(player.getState());
状态模式的优点是:
- 消除了复杂的条件分支语句
- 将状态相关的行为封装在状态类中
缺点是如果状态太少,使用状态模式会显得过于复杂。