状态模式也称状态机(State Machine),简单用一句话解释就是:用对象定义具体状态,调用时指向具体状态对象的方法。
一、类图
状态模式包含以下主要角色。
- 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为。
二、示例
用“状态模式”设计一个学生成绩的状态转换程序。包含了“不及格”“中等”和“优秀” 3 种状态,当学生的分数小于 60 分时为“不及格”状态,当分数大于等于 60 分且小于 90 分时为“中等”状态,当分数大于等于 90 分时为“优秀”状态,我们用状态模式来实现这个程序。
package state; public class ScoreStateTest { public static void main(String[] args) { ScoreContext account=new ScoreContext(); System.out.println("学生成绩状态测试:"); account.add(30); account.add(40); account.add(45); account.add(-35); account.add(-25); } } //环境类 class ScoreContext { private AbstractState state; ScoreContext() { state=new LowState(this); } public void setState(AbstractState state) { this.state=state; } public AbstractState getState() { return state; } public void add(int score) { state.addScore(score); } } //抽象状态类 abstract class AbstractState { protected ScoreContext hj; //环境 protected String stateName; //状态名 protected int score; //分数 public abstract void checkState(); //检查当前状态 public void addScore(int x) { score+=x; System.out.print("加上:"+x+"分,\t当前分数:"+score ); checkState(); System.out.println("分,\t当前状态:"+hj.getState().stateName); } } //具体状态类:不及格 class LowState extends AbstractState { public LowState(ScoreContext h) { hj=h; stateName="不及格"; score=0; } public LowState(AbstractState state) { hj=state.hj; stateName="不及格"; score=state.score; } public void checkState() { if(score>=90) { hj.setState(new HighState(this)); } else if(score>=60) { hj.setState(new MiddleState(this)); } } } //具体状态类:中等 class MiddleState extends AbstractState { public MiddleState(AbstractState state) { hj=state.hj; stateName="中等"; score=state.score; } public void checkState() { if(score<60) { hj.setState(new LowState(this)); } else if(score>=90) { hj.setState(new HighState(this)); } } } //具体状态类:优秀 class HighState extends AbstractState { public HighState(AbstractState state) { hj=state.hj; stateName="优秀"; score=state.score; } public void checkState() { if(score<60) { hj.setState(new LowState(this)); } else if(score<90) { hj.setState(new MiddleState(this)); } } }
三、优缺点
优点:
封装了转换规则。枚举可能的状态,在枚举状态之前需要确定状态种类。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。