定义:
当一个对象内在的状态改变时,允许其改变行为,这个对象看起来像是改变了其类。
状态模式不太好理解,我现在还没有完全理解,这个模式给我的第一印象就是比较乱,给我的感觉好像是两个类互相依赖,①调用②的方法,②调用①的方法,弄的好乱,所以这个状态模式就不用通用类图去描述了,那样会不知所云,还是举一个实际的例子来理解吧。
这个例子是书本上的一个例子,是针对足球队比赛时,根据比分的领先还是落后,来调整其阵型,从而进入相应的状态,其示意图如下:
其对应的类图如下:
图2 足球对的状态模式类图
解释:可以注意到FootballTeam这个类维护了一个ScoreState对象,表示FootballTeam这个类维护当前的一个状态,通过其中的changeState()方法来切换维护的状态,而改变阵型的方法changeLineUp()这个方法是足球队的行为,它只是调用当前维护状态中的changeLineUp()方法,因为具体的实现是在状态类中取实现的。而在状态类中,也有一个changeState()方法,这个行为的作用是调用FootballTeam中的changeState()方法,来改变FootballTeam所维护的状态。
所以要理解这个交叉的类图,关键要抓住两点:
1、changeLineUp()方法在状态类中实现,而在FootballTeam类中调用;
2、changeState()方法在FootballTeam类中实现,而在状态类中调用;
状态模式有什么好处呢?为什么要这样做呢?
状态模式的本质是将条件语句的各个分支封装起来,从而实现了状态逻辑与动作的分离。当分支很多时,这种模式会给代码的维护带来很大的便利。比如说要增加一个状态,采用分支的话,就要涉及到多个分支的更改。而用状态模式,只需要增加一个新的状态实现类,在这个类中定义这个状态可以切换到哪些状态,这个状态下可以有什么行为,就可以了。当要修改一个状态,只需要修改这个状态类就可以了。
状态模式的封装性非常好,状态变化放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的切换。
上面例子的源代码如下:
public abstract class ScoreState {
public abstract void changeLineUp(FootballTeam footballTeam, String score);
//这个方法是所有的子类都共有的方法,所以提取到了父类中进行实现
protected void changeState(FootballTeam footballTeam, ScoreState state){
footballTeam.changeState(state);
}
}
/*
* 平局状态,有两种可能切换的状态:
* 1、对手先进球,比分落后,这时调整阵型,状态进入比分落后状态
* 2、己方先进球,比分领先,这时调整阵型,状态进入比分领先状态
*/
public class DrawState extends ScoreState {
@Override
public void changeLineUp(FootballTeam footballTeam, String score) {
//比分落后
if(score=="lag"){
ScoreState lagState=new LagState();
super.changeState(footballTeam,lagState);
System.out.println("比分落后,阵型调整为3-4-3");
}
else if(score=="ahead"){
ScoreState aheadState=new AheadState();
super.changeState(footballTeam, aheadState);
System.out.println("比分领先,阵型调整为5-4-1");
}
}
}
/*
* 比分落后,只有一种可能切换的状态:己方进球扳平比分,比分持平,调整阵型,状态进入持平状态
*/
public class LagState extends ScoreState {
@Override
public void changeLineUp(FootballTeam footballTeam, String score) {
if(score=="draw"){
ScoreState drawState=new DrawState();
super.changeState(footballTeam, drawState);
System.out.println("比分持平,阵型调整为4-4-2");
}
}
}
/*
* 比分领先,只有一种可能切换的状态:对手进球扳平比分,比分持平,调整阵型,状态进入持平状态
*/
public class AheadState extends ScoreState {
@Override
public void changeLineUp(FootballTeam footballTeam, String score) {
if(score=="draw"){
ScoreState drawState=new DrawState();
super.changeState(footballTeam, drawState);
System.out.println("比分持平,阵型调整为4-4-2");
}
}
}
public class Client {
public static void main(String[] args) {
String score=null;
//定义一个球队,初始状态为持平状态
ScoreState drawState=new DrawState();
FootballTeam footballTeam=new FootballTeam(drawState);
//比分落后
score="lag";
footballTeam.changeLineUp(score);
//扳平比分
score="draw";
footballTeam.changeLineUp(score);
//比分领先
score="ahead";
footballTeam.changeLineUp(score);
}
}