在现实生活中,电梯是一个很常见的工具。它具备开门,关门,运行,以及停止。开门的时候电梯状态必须是停止运行的时候,不然就会出现生命危险。代码如下:
/**
* 电梯接口
*/
public interface ILift {
//定义电梯的四个状态
int OPENING_STATE = 1;//开门状态
int CLOSING_STATE = 2;//关门状态
int RUNNING_STATE = 3;//运行状态
int STOPPING_STATE = 4;//停下状态
//设置电梯状态
void setSate(int state);
//电梯操作功能
void open();//开门
void close();//关门
void run();//运行
void stop();//停止
}
/**
* 具体电梯
*/
public class Lift implements ILift{
/**
* 当前电梯状态
*/
private int state;
@Override
public void setSate(int state) {
this.state = state;
}
@Override
public void open() {
switch (state){
case OPENING_STATE:
//该状态下,开门方法无需操作
break;
case CLOSING_STATE:
//电梯在关门状态时,可以打开电梯门,并设置电梯的状态为打开
System.out.println("打开电梯门....");
setSate(OPENING_STATE);
break;
case RUNNING_STATE:
//该状态下,开门方法不可执行
break;
case STOPPING_STATE:
//电梯在停止运行状态时,可以打开电梯门,并设置电梯的状态为打开
System.out.println("打开了电梯门....");
setSate(OPENING_STATE);
break;
}
}
@Override
public void close() {
switch (state){
case OPENING_STATE:
//电梯在打开电梯门状态下,可以执行关闭操作
System.out.println("关闭电梯门....");
setSate(CLOSING_STATE);
break;
case CLOSING_STATE:
//电梯在关门状态时,无需操作
break;
case RUNNING_STATE:
//该状态下,运行一定是关门,也无需操作
break;
case STOPPING_STATE:
//电梯在停止运行状态时,也是关门的,无需操作
break;
}
}
@Override
public void run() {
switch (state){
case OPENING_STATE:
//运行方法必须确保电梯是关门状态的,所以是打开状态不会运行
System.out.println("电梯门打开中....无法运行");
break;
case CLOSING_STATE:
//电梯在关门状态时,可以运行
System.out.println("电梯运行,请站稳扶好...");
setSate(RUNNING_STATE);
break;
case RUNNING_STATE:
//该状态下,无需操作
break;
case STOPPING_STATE:
//电梯在停止运行状态时,是可以运行的
System.out.println("电梯再次运行,请站稳扶好...");
setSate(RUNNING_STATE);
break;
}
}
@Override
public void stop() {
switch (state){
case OPENING_STATE:
//电梯开门状态的时候一定已经停止运行了,无需操作
break;
case CLOSING_STATE:
//电梯在关门状态时,可以停下
System.out.println("电梯停下...");
setSate(STOPPING_STATE);
break;
case RUNNING_STATE:
//该状态下,可以使电梯停下
System.out.println("电梯停下了...");
setSate(STOPPING_STATE);
break;
case STOPPING_STATE:
//电梯在停止运行状态时,无需操作
break;
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/3df95ab6e8fb6190f82642c0a1d776da.png)
在以上案例中不难看出,试用了大量的条件判断语句,使得程序可读性变差。并且后续需要增加一个状态,比如断电状态,我们需要以上所有代码的运行逻辑。
故,我们使用状态模式
对有状态的对象,把复杂的逻辑判断提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
结构:
环境角色(Context):也称为上下文,它定义了客户端需要的接口,维护一个当前状态,并将状态相关的操作委托给当前状态对象来处理。
抽象状态角色(State):定义一个接口,用以封装环境对象中特定状态所对应的行为。
具体状态角色(Concrete Sate):实现抽象状态角色对应的行为
/**
* 状态模式 环境角色
* 状态环境
*/
public class Context {
//定义状态对象常量
public final static OpeningState OPENING_STATE = new OpeningState();
public final static ClosingState CLOSING_STATE = new ClosingState();
public final static RunningState RUNNING_STATE = new RunningState();
public final static StoppingState STOPPING_STATE = new StoppingState();
//定义当前电梯状态变量
private LiftState liftState;
public LiftState getLiftState() {
return liftState;
}
/**
* 设置当前状态对象
* @param 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();
}
}
/**
* 状态模式 抽象状态类
* 电梯状态
*/
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();
}
/**
* 状态模式 具体状态角色
* 开门状态
*/
public class OpeningState extends LiftState {
@Override
public void open() {
//电梯门是打开的,不操作
System.out.println("电梯门已打开.....");
}
@Override
public void close() {
//电梯门打开,可以执行关闭操作
super.context.setLiftState(Context.CLOSING_STATE);
super.context.close();
}
@Override
public void run() {
//电梯开门的时候不可以运行
}
@Override
public void stop() {
//电梯能开门必须是停下的
}
}
/**
* 状态模式 具体状态角色
* 关门状态
*/
public class ClosingState extends LiftState {
@Override
public void open() {
//关门状态下可以开门
super.context.setLiftState(Context.OPENING_STATE);
super.context.open();
}
@Override
public void close() {
//已经时关门状态,无需关门操作
System.out.println("电梯门关闭.....");
}
@Override
public void run() {
//关了门自然可以运行
super.context.setLiftState(Context.RUNNING_STATE);
super.context.run();
}
@Override
public void stop() {
//电梯门关了但我不按楼层
super.context.setLiftState(Context.CLOSING_STATE);
super.context.stop();
}
}
/**
* 状态模式 具体状态角色
* 运行状态
*/
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.STOPPING_STATE);
super.context.stop();
}
}
/**
* 状态模式 具体状态角色
* 停止状态
*/
public class StoppingState extends LiftState {
@Override
public void open() {
//停下的状态时可以开门的
super.context.setLiftState(Context.OPENING_STATE);
super.context.open();
}
@Override
public void close() {
//停下的时候已经是关了门的
}
@Override
public void run() {
//停下也可以继续运行
super.context.setLiftState(Context.RUNNING_STATE);
super.context.run();
}
@Override
public void stop() {
//已经停下无需操作
System.out.println("电梯停止.......");
}
}
![](https://img-blog.csdnimg.cn/img_convert/b4c2a88a81beb0d73a35b41600dd462e.png)
优缺点:
优点:
将所有有关状态的行为放到一个类中,方便新增新的状态,只需要改变状态即可改变行为
允许状态转换逻辑与状态对象合成一体。而不是一个巨大的条件语句块
缺点:
状态模式的使用必然增加类个数以及状态个数
状态模式的结构和实现比价复杂,运用不当使得程序结构和代码的混乱
对开闭模式支持的不太友好
使用场景:
当一个对象的行为取决于他的状态,并且在运行时根据状态改变其行为,可以使用状态模式。
当一个操作中有庞大的分支结构,并且这些分支结构取决于对象状态时。