博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【趣味设计模式系列】之【状态模式】
阅读量:4095 次
发布时间:2019-05-25

本文共 4994 字,大约阅读时间需要 16 分钟。

1. 简介

小说阅读网 www.7wx.org

状态模式(State Pattern),当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。简而言之,就是状态的变更引起了行为的变更

2. 图解

下图四辆汽车,分别代表汽车日常的四种状态。

开门状态:

1765702-20200101225554954-34902455.png

关门状态:

1765702-20200101225620768-276037730.png

飞奔状态:

1765702-20200101225638147-2086142266.jpg

停止状态:

1765702-20200101225704335-1033391974.png

其中,某种特定状态下,都有四个可执行操作,分别是open,close,run,stop,然后做对应的处理得下图所示。

1765702-20200104223940515-1011256235.jpg

3. 案例实现

类图如下:

1765702-20200104230906651-2117316863.jpg

  • 定义汽车抽象状态类CarState,持有类型为Context的属性,同时持有四个可执行操作,opencloserunstop方法;
  • 定义汽车抽象状态类的子类OpenningStateClosingStateRunningStateStoppingState,分别代表开门状态,关门状态,飞奔状态,停止状态;
  • 定义环境角色类Context,把状态对象声明为静态常量,有几个状态对象就声明几个静态常量,环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。具体环境角色有两个职责:处理本状态必须完成的任务,决定是否可以过渡到其他状态。

代码实现如下:

package com.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 20:10 * @Desc: 汽车状态抽象类 */public abstract class CarState {    //环境角色,封装状态变化引起的行为变化    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.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 20:23 * @Desc: 汽车开门状态类 */public class OpenningState extends CarState {    //打开汽车门    public void open() {        System.out.println("汽车门已开");    }    //关闭汽车门    public void close() {        //状态修改        super.context.setCarState(Context.closingState);        //动作委托为ClosingState来执行        super.context.getCarState().close();    }    //门开着时汽车一般不奔跑    public void run() {        System.out.println("汽车开门状态,不能奔跑");    }    //车门开着时,切换不到停止状态,因为没有四种状态中,没有开门且停止这个状态    public void stop() {        System.out.println("汽车开门状态,不能长时间开着门且处于停止状态");    }}
package com.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 20:23 * @Desc: 汽车飞奔状态类 */public class RunningState extends CarState {    //打开奔跑时不开门    public void open() {        System.out.println("车在飞奔,不能打开");    }    //奔跑时肯定是关门的    public void close() {        System.out.println("车在飞奔,已经关闭,不能再次关闭");    }    //汽车在飞奔    public void run() {        System.out.println("汽车在飞奔");    }    //汽车可以停下来    public void stop() {        //修改汽车为停止状态        super.context.setCarState(Context.stoppingState);        //停止动作委托为StoppingState类来执行        super.context.getCarState().stop();    }}
package com.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 20:23 * @Desc: 汽车关门状态类 */public class ClosingState extends CarState {    //打开汽车门    public void open() {        //修改汽车为开门状态        super.context.setCarState(Context.openningState);        //动作委托为OpenningState类来执行        super.context.getCarState().open();    }    //关闭汽车门    public void close() {        System.out.println("汽车门已关");    }    //汽车在飞奔    public void run() {        //修改汽车为飞奔状态        super.context.setCarState(Context.runningState);        //动作委托为RunningState类来执行        super.context.getCarState().run();    }    //汽车在停止    public void stop() {        //设置汽车状态为停止状态        super.context.setCarState(Context.stoppingState);        //动作委托为StoppingState类来执行        super.context.getCarState().stop();    }}
package com.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 20:19 * @Desc: 上下文环境类 */public class Context {    /**列出汽车所有状态     * openningState-开门状态 closingState-关门状态     * runningState-奔驰状态 stoppingState-停止状态     */    public static final OpenningState openningState = new OpenningState();    public static final ClosingState closingState = new ClosingState();    public static final RunningState runningState = new RunningState();    public static final StoppingState stoppingState = new StoppingState();    //定义汽车当前状态    private CarState carState;    public CarState getCarState() {        return  carState;    }    public void setCarState(CarState carState) {        this.carState = carState;        //切换状态        this.carState.setContext(this);    }    //汽车开门    public void open() {        this.carState.open();    }    //汽车关门    public void close(){        this.carState.close();    }    //汽车飞奔    public void run(){        this.carState.run();    }    //汽车停止    public void stop(){        this.carState.stop();    }}

客户端类如下:

package com.wzj.state.example1;/** * @Author: wzj * @Date: 2019/11/3 21:06 * @Desc: */public class Client {    public static void main(String[] args) {        Context context = new Context();        context.setCarState(new OpenningState());//        context.setCarState(new ClosingState());//        context.setCarState(new RunningState());//        context.setCarState(new StoppingState());        context.open();//        context.close();//        context.run();//        context.stop();    }}

执行结果如下:

当只打开Client15行的时候,分别打开11,12,13,14行的代码,会得到如下结果:
汽车为开门状态时,执行open

1765702-20200104235942069-260377116.png

汽车为关门状态时,执行open

1765702-20200104235953413-1075672315.png

汽车为飞奔状态时,执行open

1765702-20200105000002430-1937078993.png

汽车为停止状态时,执行open

1765702-20200105000013588-1984373709.png

上述结果可以看出,同样执行一个open方法,当状态的变化时导致行为的变化。

4. 状态模式总结

优点

  • 结构清晰
    避免了过多的switch...case或者if...else语句的使用,避免了程序的复杂性,提高系统的可维护性;
  • 遵循设计原则
    很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。
  • 封装性非常好
    这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
    缺点
    状态模式既然有优点,那当然有缺点了。但只有一个缺点,子类会太多,也就是类膨胀。如果一个事物有很多个状态也不稀奇,如果完全使用状态模式就会有太多的子类,不好管理,这个需要大家在项目中自己衡量。其实有很多方式可以解决这个状态问题,如在数据库中建立一个状态表,然后根据状态执行相应的操作,这个也不复杂,看大家的习惯和嗜好了。

转载地址:http://omxii.baihongyu.com/

你可能感兴趣的文章
Linux select TCP并发服务器与客户端编程
查看>>
Linux系统编程——线程池
查看>>
基于Visual C++2013拆解世界五百强面试题--题5-自己实现strstr
查看>>
Linux 线程信号量同步
查看>>
C++静态成员函数访问非静态成员的几种方法
查看>>
类中的静态成员函数访问非静态成员变量
查看>>
C++学习之普通函数指针与成员函数指针
查看>>
C++的静态成员函数指针
查看>>
Linux系统编程——线程池
查看>>
yfan.qiu linux硬链接与软链接
查看>>
Linux C++线程池实例
查看>>
shared_ptr简介以及常见问题
查看>>
c++11 你需要知道这些就够了
查看>>
c++11 你需要知道这些就够了
查看>>
shared_ptr的一些尴尬
查看>>
C++总结8——shared_ptr和weak_ptr智能指针
查看>>
c++写时拷贝1
查看>>
C++ 写时拷贝 2
查看>>
Linux网络编程---I/O复用模型之poll
查看>>
Java NIO详解
查看>>