1.定义
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
2.通用类图
角色介绍
- State 抽象状态角色:接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换
- ConcreteState 具体状态角色:每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地讲,就是本状态下要做的事情,以及本状态如何过度到其他状态
- Context 环境角色:定义客户端需要的接口,并且负责具体状态的切换
3.通用源码
抽象状态角色
public abstract class State {
//定义一个环境角色,提供子类访问
protected Context context;
//设置环境角色
public void setContext(Context _context) {
this.context = _context;
}
//行为1
public abstract void handle1();
//行为2
public abstract void handle2();
}
抽象状态中声明一个环境角色,提供各个状态类自行访问,并且提供所有状态的抽象行为,由各个实现类实现
具体状态角色
public class ConcreteState1 extends State{
@Override
public void handle1() {
//本状态下必须处理的逻辑
}
@Override
public void handle2() {
//设置当前状态为stat2
super.context.setCurrentState(Context.STATE2);
//过渡到state2,由Context实现
super.context.handle2();
}
}
public class ConcreteState2 extends State {
@Override
public void handle1() {
//设置当前状态为状态1
super.context.setCurrentState(Context.STATE1);
//过渡到state1状态,由context实现
super.context.handle1();
}
@Override
public void handle2() {
//本状态下必须要处理的逻辑
}
}
具体状态角色有两个职责:处理本状态必须完成的任务,决定是否可以过渡到其他状态。
具体环境角色
public class Context {
//定义状态
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
//当前状态
private State currentState;
//获得当前状态
public State getCurrentState() {
return currentState;
}
//设置当前状态
public void setCurrentState(State currentState) {
this.currentState = currentState;
//切换状态
this.currentState.setContext(this);
}
//行为委托
public void handle1() {
this.currentState.handle1();
}
public void handle2() {
this.currentState.handle2();
}
}
环境角色有两个不成文的约束:
- 把状态对象声明为静态常量,有几个状态对象就声明几个静态常量
- 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式
4.Demo
电梯是社会发展不可或缺的部分,电梯有开门、关门、运行、停止这几个状态。
但是电梯的每一个状态都是有条件:
- 敞门状态:按了电梯上下按钮,门会开,在这个状态下,电梯能做的只能是关门
- 闭门状态:在此状态下,只能是开门,停止,运行
- 运行状态:在此状态下,只能做停止。
停止状态:这时,电梯可以继续运行,也可以开门
这个时候如果用switch循环去判断,可想而知逻辑有多杂乱。这还是正常情况,如果电梯出故障了呢,它在运行状态时就不能做停止和开门操作。还要电梯维修的时候可以不开门,你也不能让维修人修着修着电梯跑了不是。这样你又要加多少判断。这个时候引入状态模式,就可以很方便地解决这个问题。具体代码,下次贴出。
5.优缺点
- 优点
- 结构清晰
- 避免了过多的switch…case或者if…else语句,提高了系统的可维护性
- 遵循设计原则
- 遵循了开闭原则和单一职责原则
- 封装性非常好
- 状态变换放置到类的内部实现,外部的调用不用知道类内部如何实现状态和行为的切换
- 结构清晰
- 缺点
- 子类太多,会造成类膨胀。解决问题的办法不止一种,我们也可以在数据库建立一个状态表,然后根据状态执行响应的操作。
6.应用场景
- 行为随状态改变而改变的场景
- 这也是状态模式的出发点,例如权限设计,人员的不同状态即使执行相同的行为结果也会不同
- 条件、分支判断语句的替代者
- 程序中大量使用switch语句或者if语句导致 程序结构不清晰,逻辑混乱。
- 注意:
- 使用状态模式时对象的状态最好不超过5个