定义:
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。状态模式的核心是封装,由于对象内部状态的改变,从而使这个类改变了其行为,看起来就像是换了一个类一样。
三个角色:
接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。
每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。
定义客户端需要的接口,并且负责具体状态的切换。
代码示例:
package com.statechanges;
/**
* 环境角色
*/
public class Context {
//电梯状态
public final static OpenningState openningState = new OpenningState();
public final static CloseingState closeingState = new CloseingState();
public final static RunningState runningState = new RunningState();
public final static StoppingState stoppingState = new StoppingState();
//定义当前电梯状态
private LiftState liftState;
public LiftState getLiftState() {
return liftState;
}
public void setLiftState(LiftState 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();
}
}
package com.statechanges;
/**
* 抽象电梯状态类
*/
public 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();
}
package com.statechanges;
public class OpenningState extends LiftState {
//打开电梯
@Override
public void open() {
System.out.println("电梯门开启");
}
@Override
public void close() {
//状态修改
super.context.setLiftState(Context.closeingState);
//动作委托为CloseState来执行
super.context.getLiftState().close();
}
@Override
public void run() {
}
@Override
public void stop() {
}
}
package com.statechanges;
public class CloseingState extends LiftState {
//电梯门关了再打开
@Override
public void open() {
super.context.setLiftState(Context.openningState);//设置为敞门状态
super.context.getLiftState().open();
}
@Override
public void close() {
System.out.println("电梯门关闭");
}
//电梯门关了,电梯开始运行
@Override
public void run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState);
super.context.getLiftState().stop();
}
}
package com.statechanges;
public class RunningState extends LiftState {
//电梯运行期间,电梯门是关着的
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public void run() {
System.out.println("电梯正在上下运行");
}
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState);
super.context.getLiftState().stop();
}
}
package com.statechanges;
public class StoppingState extends LiftState {
@Override
public void open() {
super.context.setLiftState(Context.openningState);//设置为敞门状态
super.context.getLiftState().open();
}
@Override
public void close() {
}
@Override
public void run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
@Override
public void stop() {
System.out.println("电梯停止了");
}
}
package com.statechanges;
/**
* 状态模式
*/
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setLiftState(new CloseingState());
context.open();
context.close();
context.run();
context.stop();
}
}
//打印结果
电梯门开启
电梯门关闭
电梯正在上下运行
电梯停止了
总结:
优点:
结构清晰:避免了过多的switch...case或者if...else语句的使用,避免了程序的复杂性,提高系统的可维护性。
遵循设计原则:很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,增加状态就要增加子类,修改状态,只修改一个子类就可以。
封装性非常好:这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
缺点:
随着状态的增多,子类会变得更多,所以需要权衡状态值得设定,如果无法限制可以预先在数据库存储,这样就更有利于状态模式的使用。
摘自《设计模式之禅》 |