十六、状态模式—用类表示状态 #和设计模式一起旅行#

人有悲欢离合,月有阴晴圆缺!

故事背景

白天、黑夜是不同的状态,水蒸气、冰是水不同的状态,大千的世界,不同的各种东西会有很多种状态,本篇要介绍的就是 “用类来表示状态”,用类表示状态后,我们就可以切换类来方便地改变对象的状态。

故事主角

状态模式:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

状态模式类图

在状态模式结构中包括几个角色:
- Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。
- State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法。
- ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态。

状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。

状态模式和策略模式是双胞胎,在出生的时候才分开。

注意:状态转换有两种方式
1. 统一由环境类来负责状态之间的转换
2. 由具体状态类来负责状态之间的转换

武功修炼

武功修炼我们看一个电梯的例子:

一个电梯有四个动作:开门、关门、运行、停止。

门开状态:在这个状态下电梯只能做的动作是关门动作!

门闭状态:电梯门关闭了,在这个状态下,可以进行的动作是:开门(我不想坐电梯了)、停止(忘
记按路层号了)、运行!

运行状态:电梯正在跑,上下窜,在这个状态下,电梯只能做的是停止!

停止状态:电梯停止不动,在这个状态下,电梯有两个可选动作:继续运行和开门动作;

电梯运行状态图

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

    @Override
    public void close() {
    // 电梯门开启状态,则当然可以进行关闭操作
        super.context.setLiftState(Context.closeingState);
        super.context.getLiftState().close();

    }

    @Override
    public void run() {
        //do nothind
    }

    @Override
    public void stop() {
        //do nothind
    }

}
public class ClosingState extends LiftState {
    //电梯门关闭,这是关闭状态要实现的动作
    @Override
    public void close() {
        System.out.println("电梯门关闭...");
    }
    //电梯门关了再打开,逗你玩呢,那这个允许呀
    @Override
    public void open() {
        super.context.setLiftState(Context.openningState); //置为门敞状态
        super.context.getLiftState().open();
    }

    //电梯门关了就跑,这是再正常不过了
    @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();
    }
}

public class RunningState extends LiftState {
    //电梯门关闭?这是肯定了
    @Override
    public void close() {
    //do nothing
    }
    //运行的时候开电梯门?你疯了!电梯不会给你开的
    @Override
    public void open() {
    //do nothing
    }
    //这是在运行状态下要实现的方法
    @Override
    public void run() {
        System.out.println("电梯上下跑...");
    }
    //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
    @Override
    public void stop() {
        super.context.setLiftState(Context.stoppingState); //环境设置为停止状态;
        super.context.getLiftState().stop();
    }
}


public class StoppingState extends LiftState {
    //停止状态关门?电梯门本来就是关着的!
    @Override
    public void close() {
        //do nothing;
    }
    //停止状态,开门,那是要的!
    @Override
    public void open() {
        super.context.setLiftState(Context.openningState);
        super.context.getLiftState().open();
    }
    //停止状态再跑起来,正常的很
    @Override
    public void run() {
        super.context.setLiftState(Context.runningState);
        super.context.getLiftState().run();
    }

    //停止状态是怎么发生的呢?当然是停止方法执行了
    @Override
    public void stop() {
        System.out.println("电梯停止了...");
    }
}

public class TestClient {

    public static void main(String[] args) {
        Context context = new Context();
        // 设置电梯的初始化状态为关闭
        context.setLiftState(new ClosingState());
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}


电梯门开启....
电梯门关闭...
电梯上下跑...
电梯停止了...

此例子来自于-Java设计模中!
此例中使用环境类切换状态!

总结

优点:
- 封装了状态的状态的转换
- 将所有与状态相关的行为放到一个类中
- 多个环境可以共享也给状态对象

缺点:
- 状态太多的话,增加系统的类的数量,导致系统开销增大
- 使用不恰当,导致程序结构和代码混乱

适合场景:
- 对象的行为依赖它的状态,状态的改变将导致行为的变化。
- 在代码中包含大量与对象状态有关的条件语句(if-else 或者 switch 等),这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。

Next 期待下一篇吧!下一篇讲讲责任链模式!

参考

本专栏文章列表

一、设计模式-开篇—为什么我要去旅行? #和设计模式一起旅行#
二、设计模式-必要的基础知识—旅行前的准备 #和设计模式一起旅行#
三、设计模式介绍—她是谁,我们要去哪里? #和设计模式一起旅行#
四、单例模式—不要冒充我,我只有一个! #和设计模式一起旅行#
五、工厂模式—旅行的钱怎么来 #和设计模式一起旅行#
六、策略模式—旅行的交通工具 #和设计模式一起旅行#
七、观察者模式——关注我,分享旅途最浪漫的瞬间! #和设计模式一起旅行#
八、装饰者模式—巴厘岛,奶茶店的困扰! #和设计模式一起旅行#
九、命令模式—使用命令控制奶茶店中酷炫的灯 #和设计模式一起旅行#
十、模板方法模式—制作更多好喝的饮品! #和设计模式一起旅行#
十一、代理模式 —专注,做最好的自己!#和设计模式一起旅行#
十二、适配器模式——解决充电的烦恼 #和设计模式一起旅行#
十三、外观模式—— 简化接口 #和设计模式一起旅行#
十四、迭代器模式—— 一个一个的遍历 #和设计模式一起旅行#
十五、组合模式—— 容器与内容的一致性 #和设计模式一起旅行#
十六、状态模式—用类表示状态 #和设计模式一起旅行#
十七、访问者模式-访问数据结构并处理数据 #和设计模式一起旅行#
十八、职责链模式-推卸责任,不关我的事,我不管!#和设计模式一起旅行#
十九、原型模式—通过复制生产实例 #和设计模式一起旅行#
二十、设计模式总结—后会有期 #和设计模式一起旅行#


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页