假设我们正在做一个即时战略游戏,我们设计一个兵种,他在刚刚生产出来的时候是步兵,但是他可以切换武器,第一次切换会变成弓箭手,第二次切换会变成举着盾牌的装甲兵,第三次切换则又变成了步兵……如何实现这个切换的机制?我们一开始会想到,在步兵这个类中加入switch语句,然而这样的话,代码不利于扩展,不利于修改,这时我们就可以使用状态模式了。
状态模式允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
在本例中,这个兵种有3个状态――步兵、弓箭手和装甲兵。我们将这3个状态都继承于同一个基类SoldierState,我们还需要定义一个兵种类来包含一个SoldierState对象,以便它是用来存储这些状态的,在本例中这个类的名字叫做KnightContext。先看Java代码吧:
abstract class SoldierState {
public abstract void show();
protected void changeState(KnightContext knight, SoldierState soldierState){
knight.changeState(soldierState);
}
public abstract void transform(KnightContext knight);
}
class KnightContext {
SoldierState state;
public KnightContext(){
state = SwordState.getState();
}
public void changeState(SoldierState state){
this.state = state;
state.show();
}
public void transform(){
state.transform(this);
}
}
class SwordState extends SoldierState{
private static SoldierState state = new SwordState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("现在是步兵模式。");
}
public void transform(KnightContext knight) {
changeState(knight, BowState.getState());
}
}
class BowState extends SoldierState{
private static SoldierState state = new BowState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("现在是弓箭模式。");
}
public void transform(KnightContext knight) {
changeState(knight, ShieldState.getState());
}
}
class ShieldState extends SoldierState{
private static SoldierState state = new ShieldState();
public static SoldierState getState(){
return state;
}
public void show() {
System.out.println("现在是盾牌模式。");
}
public void transform(KnightContext knight) {
changeState(knight, SwordState.getState());
}
}
public class State
{
public static void main(String[] args) {
KnightContext knight = new KnightContext();
knight.transform();
knight.transform();
knight.transform();
knight.transform();
knight.transform();
}
SwordState、BowState、ShieldState为此兵种的三个状态。KnightContext中有个SoldierState类型的成员state表示这个兵种的当前状态。请注意,我们并不希望把如何切换的过程写在KnightContext中(一般的想法可能是,在changeState中加入switch块,这样会使得KnightContext过于繁重),而是把如何转换写在了SoldierState的transform方法中。这样就避免了在KnightContext中加入大量的切换状态的代码。如果需要新增加一个状态,只需要修改和增加SoldierState的子类即可。对于每一个状态,它都有一个单独的子类来表示,因此在状态多的情况下会出现很多个子类,这也是状态模式的缺点。
程序运行的结果为:
现在是弓箭模式。
现在是盾牌模式。
现在是步兵模式。
现在是弓箭模式。
现在是盾牌模式。
以上便是状态模式的说明,希望能够对大家有所帮助。