什么是状态模式
对象内部状态改变时,行为随之改变,看起来像是改变了整个类
例如水有固态、液态、气态三种状态,固态时为冰,行为包括融化、雕刻,液态时为水,行为包括流动、蒸发,气态时为水蒸气,行为包括液化、扩散
什么时候使用状态模式
a)、对象的行为依赖于状态,状态改变,行为也会改变
b)、现有的代码中包含大量的if else语句,根据对象的状态,执行不同分支
举例说明
现在有一款纸牌游戏,用户角色有入门级、熟练级、高手级、骨灰级四个级别,用户积分决定级别,不同级别能力不同。全部级别都可以play(),熟练级可以积分翻倍doubleScore(),高手级可以换牌changeCards(),骨灰级可以偷看别人的牌peekCards()
实现如下:
1、纸牌游戏类中包含全部四种级别,初始状态为入门级,每次play()后根据结果增加积分或者减少积分,积分变更后在changeState()方法中根据积分更新级别
public class CardGame {
private String playerName;
private int points = 0;
private Level level;
final private PrimaryLevel primaryLevel;
final private SecondaryLevel secondaryLevel;
final private ProfessionalLevel professionalLevel;
final private FinalLevel finalLevel;
public CardGame(String name) {
System.out.println(name + " starts the card game!");
playerName = name;
level = new PrimaryLevel(this);
primaryLevel = new PrimaryLevel(this);
secondaryLevel = new SecondaryLevel(this);
professionalLevel = new ProfessionalLevel(this);
finalLevel = new FinalLevel(this);
}
public void play() {
System.out.println(level.getClass().getSimpleName() + " play card game!");
level.play();
}
public void doubleScore() {
level.doubleScore();
}
public void changeCards() {
level.changeCards();
}
public void peekCards() {
level.peekCards();
}
public int getPoints() {
return points;
}
public void gainPoints(int points) {
this.points += points;
changeState();
}
public void losePoints(int points) {
this.points -= points;
this.points = Math.max(this.points,0);
changeState();
}
private void changeState() {
if (points >= 300) {
level = finalLevel;
} else if (points >= 200) {
level = professionalLevel;
} else if (points >= 100) {
level = secondaryLevel;
} else {
level = primaryLevel;
}
System.out.println("level changes to " + level.getClass().getSimpleName());
}
}
2、用户级别的基本抽象类如下,级别类中需要持有纸牌游戏类吗,用于更新用户积分
abstract public class Level {
protected CardGame game;
public abstract void play();
public abstract void doubleScore();
public abstract void changeCards();
public abstract void peekCards();
}
具体实现类,例如入门级如下,其他具体实现类类似:
public class PrimaryLevel extends Level {
public PrimaryLevel(CardGame game) {
this.game = game;
}
@Override
public void play() {
boolean isSuccess = new Random().nextBoolean();
if (isSuccess) {
game.gainPoints(100);
} else {
game.losePoints(100);
}
}
@Override
public void doubleScore() {
System.out.println("PrimaryLevel does not support doubleScore!");
}
@Override
public void changeCards() {
System.out.println("PrimaryLevel does not support changeCards!");
}
@Override
public void peekCards() {
System.out.println("PrimaryLevel does not support peekCards!");
}
}
测试代码:
CardGame cardGame = new CardGame("David");
cardGame.play();
cardGame.play();
cardGame.doubleScore();
cardGame.changeCards();
cardGame.play();
cardGame.play();
cardGame.changeCards();
cardGame.peekCards();
测试结果:
David starts the card game!
PrimaryLevel play card game!
level changes to SecondaryLevel
SecondaryLevel play card game!
level changes to ProfessionalLevel
ProfessionalLevel doubleScore!
level changes to FinalLevel
FinalLevel changeCards!
FinalLevel play card game!
level changes to FinalLevel
FinalLevel play card game!
level changes to FinalLevel
FinalLevel changeCards!
FinalLevel peekCards!
从实现中可以看到状态模式主要包含三个角色:环境类、抽象状态类以及具体状态类
抽象状态类负责定义基本行为,不同的具体状态类表示不同的状态,对各种行为有自己不同的实现
环境类和状态类互相持有,环境类执行状态类中的方法,状态类更新环境类中的数据
使用状态模式的好处:
1、集中处理状态转换,而不是分散在各个代码块中,而且可以将状态转换代码和业务代码分开
2、将与某个状态有关的行为统一放到一个类中,只需注入一个类对象即可使环境具备该状态下的所有行为
3、多个环境类可以共享状态对象(将状态类定义为静态对象即可)
缺点:
1、增加系统中类和对象的个数,增大系统开销
2、增大系统设计难度