状态模式的定义是:当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了自身所属的类。
该模式适合于对象具有有限的状态,并且在状态之间相互切换。
例如使用如下的条件分支语句也是属于状态的切换:
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());
状态模式的优点是:
- 消除了复杂的条件分支语句
- 将状态相关的行为封装在状态类中
缺点是如果状态太少,使用状态模式会显得过于复杂。