设计模式 -- 状态模式

在现实生活中,电梯是一个很常见的工具。它具备开门,关门,运行,以及停止。开门的时候电梯状态必须是停止运行的时候,不然就会出现生命危险。代码如下:

/**
 * 电梯接口
 */
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;
        }
    }
}

在以上案例中不难看出,试用了大量的条件判断语句,使得程序可读性变差。并且后续需要增加一个状态,比如断电状态,我们需要以上所有代码的运行逻辑。

故,我们使用状态模式

对有状态的对象,把复杂的逻辑判断提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

结构:

环境角色(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("电梯停止.......");
    }
}

优缺点:

优点:

将所有有关状态的行为放到一个类中,方便新增新的状态,只需要改变状态即可改变行为

允许状态转换逻辑与状态对象合成一体。而不是一个巨大的条件语句块

缺点:

状态模式的使用必然增加类个数以及状态个数

状态模式的结构和实现比价复杂,运用不当使得程序结构和代码的混乱

对开闭模式支持的不太友好

使用场景:

当一个对象的行为取决于他的状态,并且在运行时根据状态改变其行为,可以使用状态模式。

当一个操作中有庞大的分支结构,并且这些分支结构取决于对象状态时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值