状态模式State(对象行为型)
解决问题
随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱。维护也会很麻烦。那么我就考虑只修改自身状态的模式。
方案
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
一个对象的行为取决于一个或多个动态变化的属性 ,这样的属性叫做 状态 ,这样的对象叫做 有状态的 ( stateful ) 对象 ,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
结构
- 环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
- 抽象状态类(State): 定义一个接口以封装与Context的一个特定状态相关的行为。
- 具体状态类(ConcreteState): 每一子类实现一个与Context的一个状态相关的行为。
适用性
- 一个对象的行为取决于它的状态
- 代码中包含大量与对象状态有关的条件语句: 一个操作中含有庞大的多分支的条件( if else(或switch case)语句,且这些分支依赖于该对象的状态。
优缺点
优点
它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来,将每一个状态转换和动作封装到一个类中,就把着眼点从执行状态提高到整个对象的状态。
它使得状态转换显式化,为不同的状态引入独立的对象使得转换变得更加明确。
State对象可被共享,各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象。
缺点
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
经典案例
电梯模型
abstract class LiftState {
//定义一个环境角色,也就是封装状态的变化引起的功能变化
protected Context context;
public void setContext(Context _context) {
this.context = _context;
}
//电梯开门动作
public abstract void open();
//电梯关门动作
public abstract void close();
//电梯运行动作
public abstract void run();
//电梯停止动作
public abstract void stop();
}
class OpenningState{
//开启当然可以关闭了,我就想测试一下电梯门开关功能
@Override
public void open() {
System.out.println("电梯门开启...");
}
@Override
public void close() {//虽然可以关门,但这个动作不归我执行
//状态修改
super.context.setLiftState(Context.closeingState);
//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
super.context.getLiftState().close();
}
//电梯门不能开着就跑,这里什么也不做
@Override
public void run() {
//do nothing
}
//开门状态已经是停止的了
@Override
public void stop() {
//do nothing
}
}
class CloseingState{
@Override
public void open() {
super.context.setLiftState(Context.openningState);
super.context.getLiftState().open();
}
@Override
public void close() {
System.out.println("电梯门关闭...");
}
//电梯门不能开着就跑,这里什么也不做
@Override
public void run() {
//do nothing
}
//开门状态已经是停止的了
@Override
public void stop() {
//do nothing
}
}
// 省略运行与停止实现类.
class Context{
//定义出所有的电梯状态
public final static OpenningState openningState = new OpenningState();//开门状态,这时候电梯只能关闭
public final static ClosingState closeingState = new ClosingState();//关闭状态,这时候电梯可以运行、停止和开门
public final static RunningState runningState = new RunningState();//运行状态,这时候电梯只能停止
public final static StoppingState stoppingState = new StoppingState();//停止状态,这时候电梯可以开门、运行
//定义一个当前电梯状态
private Listate liftState;
public Listate getLiftState() {
return this.liftState;
}
public void setLiftState(Listate liftState) {
//当前环境改变
this.liftState = liftState;
//把当前的环境通知到各个实现类中
this.liftState.setContext(this);
}
public void open() {
this.liftState.open();
}
public void close() {
this.liftState.close();
}
public void run() {
this.liftState.run();
}
public void stop() {
this.liftState.stop();
}
}