设计模式——状态模式

前言

设计模式是指导一个程序猿以更好的姿态处理一些问题,而不再像刚学编程的我们,只会使用if-else分支语句,或是使用硬干的骚操作完成需求。不使用设计模式,一来是代码逻辑会越来越晦涩难懂(到了某天你会发现自己也没办法看清楚所有逻辑),二来是代码维护成本越来越高(你的加班时间会越来越长),三来是可以装bility。基于这么多的好处,小盆友和大家一起讨论和分享下设计模式,让自己不再是一个坐在电脑前敲代码的码农。

讲个故事——“古怪的电梯”

老样子,讲设计模式前,先来个场景(讲不出故事了。。只能尬聊了?)

设想一下,用程序来表达一个电梯的普通运转流程:关门->运行->停止->开门。这是最为正常的使用流程,乘坐电梯的人进入后,电梯关门,然后电梯运行将人送至目的层数,停止,然后开门。
但是有个问题就是,这只是一般流程,乘坐电梯的人也可以玩弄电梯:开门->关门->再开门->再关门;或是运行->停止->运行->开门等等等等。
总之,乘坐电梯的人操作流程有很多,也就是这四种状态是可以相互转换的。但是,细想一下,也不是很周全,因为正常情况下,开门的状态下是不能运行的,运行状态下不能开门,也就是说,四种状态中,有些状态不能转换。我们就这四种状态的转换画一个表格:

开门open运行run停止stop关门close
正开着门✖️✖️✖️☑️
运行中✖️✖️☑️✖️
停止☑️☑️✖️✖️
已经关门☑️☑️☑️✖️

看到这张表格,想必大家此时心中已经有千万种实现方式,有些小伙伴可能会用到大量的 switch-case 或 if-else的分支语句进行区分状态的转换流程,这里就不给出此类代码(请允许我的懒惰?️),只是略微吐槽一下,如果用了大量的分支语句,弊端是显而易见的:

  1. 扩展性差,当增加一种状态,需要改动的地方多
  2. 逻辑耦合,不易维护;
  3. 不能装逼!!!!

有经验的小伙伴,很快会想到使用状态模式。在这种行为随状态改变而改变的情况,可以考虑使用“状态模式”。先给出状态模式的类图
状态模式
可以看出,状态主要由三部分组成:

  1. State:状态的抽象类
  2. ConcreteState:状态的具体实现类,主要负责实现当前状态的逻辑实现,还有过度到其他状态的逻辑控制(如果不能过度就空实现)
  3. Context:环境角色,负责管理状态

接下来,我们对上面的场景进行映射

可以看到,映射的类图其实没有多大的变动,主要的状态转变逻辑会在各自的具体状态实现类中,例如:OpenState转变为CloseState,是由OpenState来维护(将Context的当前状态进行切换),并且打开的逻辑是由OpenState来实现。而Context用于管理调用各自具体的状态。可能现在你有些凌乱,我们可以先进入编码时刻,结合具体代码来理解这段话。

编码时刻

先看看抽象状态类,主要是规范所有具体状态,而且持有一个状态管理

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 OpenState extends LiftState {
    @Override
    public void open() {
       System.out.println("电梯门开启...");
    }

    @Override
    public void close() {
        super.context.setLiftState(Context.CLOSE_STATE);
        super.context.close();
    }

    @Override
    public void run() {  //空实现,因为当前状态无法转到run }

    @Override
    public void stop() { //空实现,因为当前状态无法转到stop }
}
public class RunState extends LiftState {
    @Override
    public void open() { //空实现,因为当前状态无法转到open}

    @Override
    public void close() { //空实现,因为当前状态无法转到close }

    @Override
    public void run() {
        System.out.println("电梯上下运行...");
    }

    @Override
    public void stop() {
        super.context.setLiftState(Context.STOP_STATE);
        super.context.stop();
    }
}
public class StopState extends LiftState {
    @Override
    public void open() {
        super.context.setLiftState(Context.OPEN_STATE);
        super.context.open();
    }

    @Override
    public void close() {  //空实现,因为当前状态无法转到close  }

    @Override
    public void run() {
        super.context.setLiftState(Context.RUN_STATE);
        super.context.run();
    }

    @Override
    public void stop() {
        System.out.println("电梯停止了...");
    }
}
public class CloseState extends LiftState {
    @Override
    public void open() {
        super.context.setLiftState(Context.OPEN_STATE);
        super.context.open();
    }

    @Override
    public void close() {
        System.out.println("电梯门关闭...");
    }

    @Override
    public void run() {
        super.context.setLiftState(Context.RUN_STATE);
        super.context.run();
    }

    @Override
    public void stop() {
        super.context.setLiftState(Context.STOP_STATE);
        super.context.stop();
    }
}

状态管理类

public class Context {
    public final static OpenState OPEN_STATE = new OpenState();
    public final static CloseState CLOSE_STATE = new CloseState();
    public final static RunState RUN_STATE = new RunState();
    public final static StopState STOP_STATE = new StopState();

    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();
    }
}

最后是调用代码:

public class Main {
    public static void main(String[] args) {
        Context context = new Context();
        context.setLiftState(Context.CLOSE_STATE);
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

运行结果
运行结果

总结

在这里使用状态模式的好处是,让各自的状态逻辑分成不同的类,维护起来清晰。而且扩展方便,只需要添加一个继承LiftState的类,在Context中增加这个状态即可使用。但是,这里也就暴露了一个状态模式的缺点,当状态较多时,具体的状态类会非常多。所以建议状态最好不超过5个,但只是建议,毕竟程序是死的,人是活的。希望这篇文章,能给你一些启发,减少一些些分支语句,让代码优雅起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值